前言,我這里驗證的nginx-v1.23.2單機環境下的nginx中的正則表達式、location路徑匹配規則和優先級。
先準備好環境,基礎配置是這樣 nginx/conf/conf.d/host.conf :
server {
listen 8081;
server_name 10.90.5.70;
proxy_connect_timeout 60;
proxy_read_timeout 600;
proxy_send_timeout 600;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto "http";
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_next_upstream error non_idempotent;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
下面的案例都是基于以上配置驗證的。
一,nginx中的正則表達式
nginx中的正則表達式基本遵循了Regular Expression格式和規則。不同的是,一般以特殊字符代表正則表達式的開始,即標識要用Regular Expression處理其后的字符。
nginx里面可以使用正則表達式的部分可以是 server里,或者location 路徑上。
常見的正則表達式的含義
^ :匹配輸入字符串的起始位置
$ :匹配輸入字符串的結束位置
. :匹配除“\n”之外的任何單個字符,若要匹配包括“\n”在內的任意字符,請使用諸如“[.\n]”之類的模式
\d :匹配純數字
\w :匹配字母或數字或下劃線或漢字
\s :匹配任意的空白符
\b :匹配單詞的開始或結束
【下面這部分是標注匹配長度(字符數量、重復數量)的】
* :匹配前面的字符零次或多次。如“ol*”能匹配“o”及“ol”、“oll”
+ :匹配前面的字符一次或多次。如“ol+”能匹配“ol”及“oll”、“olll”,但不能匹配“o”
? :匹配前面的字符零次或一次,例如“do(es)?”能匹配“do”或者“does”,”?”等效于”{0,1}”
{n} :重復 n 次
{n,} :重復 n 次或更多次
{n,m} :重復 n 到 m 次
[] :定義匹配的字符范圍
[c] :匹配單個字符 c
注意:在括號里面用-表示范圍:
[a-z] :匹配 a-z 小寫字母的任意一個
[a-zA-Z0-9] :匹配所有大小寫字母或數字
() :表達式的開始和結束位置 例如:(jpg|gif|swf|)
| :或運算符
! :非運算符(與其后面的表達式去反運算)
正則表達式里面沒有“與運算符”。
\ :轉義字符,將后面接著的字符標記為一個特殊字符或一個原義字符或一個向后引用。如“\n”匹配一個換行符,而“\$”則匹配“$”
參考鏈接:https://www.jb51.net/article/149053.htm
二,location路徑匹配規則和優先級
location:用來設置請求的URI。nginx中location配置項是最基礎的配置,而且它的配置也稍顯復雜。
location匹配規則 與 優先級
默認值 /
語法 location [ = | ~ | ~* | ^~ ] uri { ... }
位置 server,location
uri變量是待匹配的請求字符串,可以不包含正則表達式,也可以包含正則表達式。那么:
nginx服務器在搜索匹配location的時候,是先使用不包含正則表達式進行匹配,找到一個匹配度最高的一個,然后在通過包含正則表達式的進行匹配,如果能匹配到直接訪問,匹配不到,就使用剛才匹配度最高的那個location來處理請求。
另一種描述,意思是一樣的:
location 匹配的優先級(與location在配置文件中的順序無關)
= 精確匹配會第一個被處理。如果發現精確匹配,nginx停止搜索其他匹配。
普通字符匹配,正則表達式規則和長的塊規則將被優先和查詢匹配,也就是說如果該項匹配還需去看有沒有正則表達式匹配和更長的匹配。
^~ 則只匹配該規則,nginx停止搜索其他匹配,否則nginx會繼續處理其他location指令。
最后匹配理帶有"~"和"~*"的指令,如果找到相應的匹配,則nginx停止搜索其他匹配;
當沒有正則表達式或者沒有正則表達式被匹配的情況下,那么匹配程度最高的逐字匹配指令會被使用。
location 優先級官方文檔:
1. Directives with the = prefix that match the query exactly. If found, searching stops.
2. All remaining directives with conventional strings, longest match first. If this match used the ^~ prefix, searching stops.
3. Regular expressions, in order of definition in the configuration file.
4. If #3 yielded a match, that result is used. Else the match from #2 is used.
1. =前綴的指令嚴格匹配這個查詢。如果找到,停止搜索。
2. 所有剩下的常規字符串,最長的匹配。如果這個匹配使用^?前綴,搜索停止。
3. 正則表達式,在配置文件中定義的順序。
4. 如果第3條規則產生匹配的話,結果被使用。否則,如同從第2條規則被使用。
它包含了路徑的匹配規則和針對該規則的配置。
location規則按照前導符主要分五類:
| | |
---|
| | 全字匹配,只有當請求路徑和uri完全匹配時,對應的規則才會生效 |
| | |
| | |
| | |
| | |
這五類規則,同時存在配置文件中時,按照一定的優先級規則生效。
優先級:( location = ) > ( location 完整路徑 ) > ( location ^~ 否定正則 ) > ( location ~* 正則順序 ) > ( location ~ 區分大小寫正則順序 ) > ( location 部分起始路徑 ) > ( / )
優先級:① > ④ > ③ > ② > ⑤
nginx規則決定流程如下圖:

文字說明:
以下說明非常關鍵
一、檢查請求uri是否與某個=規則匹配,如果有,直接應用規則,終止后續匹配。
二、nginx首先檢查所有路徑匹配規則配置項,包括"^~"規則和沒有前導符號的規則,選擇并記住和當前請求uri匹配度最長的配置項。但這個時候,并不會啟用相關的配置,而僅僅是記住。
三、判斷上一步中選擇下來的路徑規則是否包含 ^~ ,如果包含,則使用該條規則,終止后續匹配。
四、按配置順序進行正則表達式檢查,匹配到第一條合適的正則表達式時,使用該條規則,終止后續匹配。
五、使用步驟三選擇出來的路徑匹配規則。
下面以實例屬性介紹:
1,不帶符號,要求必須以指定模式開始
location指令實例:
server {
listen 8081;
server_name 127.0.0.1;
# 不帶符號,要求必須以指定模式開始(區分大小寫,并且后面帶/是有區別的)
location /aaa {
default_type text/plain;
return 200 "access success aaa \n\r";
}
}
# 能匹配到:
http://127.0.0.1:8081/aaa
http://127.0.0.1:8081/aaa/
http://127.0.0.1:8081/aaadef
http://127.0.0.1:8081/aaa/def/
http://127.0.0.1:8081/aaa?p1=TOM
# 不能匹配到(大小寫區分):
http://127.0.0.1:8081/Aaa
# 如果規則(后面跟/目錄符號) location /aaa/ { 則只能匹配到下面兩行:
http://127.0.0.1:8081/aaa/
http://127.0.0.1:8081/aaa/def/
如圖:

2,= 用于不包含正則表達式的uri前,必須與指定的模式精確匹配
實測,等于號后面有或沒有空格不影響效果。location指令實例:
server {
listen 8081;
server_name 127.0.0.1;
# = : 用于不包含正則表達式的uri前,必須與指定的模式精確匹配(區分大小寫,并且后面帶/是有區別的)
location = /bbb {
default_type text/plain;
return 200 "access success bbb \n\r";
}
}
# 能匹配到:
http://127.0.0.1:8081/bbb
http://127.0.0.1:8081/bbb?p1=TOM
# 不能匹配到(大小寫區分):
http://127.0.0.1:8081/bbb/
http://127.0.0.1:8081/bbbcd
http://127.0.0.1:8081/Bbb
如圖:

3,包含正則表達式的
~ :用于表示當前uri中包含了正則表達式,并且區分大小寫
~*: 用于表示當前uri中包含了正則表達式,并且不區分大小寫
換句話說,如果uri包含了正則表達式,需要用上述兩個符合來標識
^~: 用于不包含正則表達式的uri前,功能和不加符號的一致,唯一不同的是,如果模式匹配,那么就停止搜索其他模式了。(可用它提升優先級
)
含正則表達式的location指令,實例一:
server {
listen 8081;
server_name 127.0.0.1;
# ~ :用于表示當前uri中包含了正則表達式,并且區分大小寫
# 正則表達式:區分大小寫,以/abc開頭,以1個字母或數字或下劃線或漢字結束的
location ~^/eee\w$ {
default_type text/plain;
return 200 "access success. 000 Regular expression matched: eee \n\r";
}
}
# 能匹配到:
http://127.0.0.1:8081/eeeb
http://127.0.0.1:8081/eeeB
http://127.0.0.1:8081/eee2
# 不能匹配到(大小寫區分):
http://127.0.0.1:8081/eee
http://127.0.0.1:8081/Eee
http://127.0.0.1:8081/eee/
http://127.0.0.1:8081/eeedef
http://127.0.0.1:8081/eee/def/
http://127.0.0.1:8081/eee?p1=TOM
如圖:

含正則表達式的location指令,實例二:
server {
listen 8081;
server_name 127.0.0.1;
# ~*: 用于表示當前uri中包含了正則表達式,并且不區分大小寫
# 正則表達式:不區分大小寫,以/abc開頭,以字母或數字或下劃線或漢字結束的
location ~*^/ddd\w$ {
default_type text/plain;
return 200 "access success. 111 Regular expression matched: ddd \n\r";
}
}
# 能匹配到:
http://127.0.0.1:8081/dddb
http://127.0.0.1:8081/dddB
http://127.0.0.1:8081/ddd2
http://127.0.0.1:8081/DddH
# 不能匹配到(大小寫區分):
http://127.0.0.1:8081/ddd
http://127.0.0.1:8081/Ddd
http://127.0.0.1:8081/ddd/
http://127.0.0.1:8081/ddddef
http://127.0.0.1:8081/ddd/def/
http://127.0.0.1:8081/ddd?p1=TOM
如圖:

不包含正則表達式的location指令,實例三:
server {
listen 8081;
server_name 127.0.0.1;
# ^~: 用于不包含正則表達式的uri前,功能和不加符號的一致,唯一不同的是,如果模式匹配,那么就停止搜索其他模式了,可用于提升優先級。(區分大小寫,并且后面帶/是有區別的)
location ^~ /fff {
default_type text/plain;
return 200 "access success. Non Regular expression matched: fff \n\r";
}
}
# 能匹配到:
http://127.0.0.1:8081/fff
http://127.0.0.1:8081/fff/
http://127.0.0.1:8081/fffdef
http://127.0.0.1:8081/fff/def/
http://127.0.0.1:8081/fff?p1=TOM
# 不能匹配到(大小寫區分):
http://127.0.0.1:8081/Fff
http://127.0.0.1:8081/pp/fff
# 如果規則(后面跟/目錄符號) location /fff/ { 則只能匹配到下面兩行:
http://127.0.0.1:8081/fff/
http://127.0.0.1:8081/fff/def/
如圖:

定義一個命名的 location
用"@" 定義一個命名的 location,使用在內部定向時,例如:error_page, try_files
@location 例子:
# 示例:404錯誤頁將被內部重定向
error_page 404 = @fetch;
location @fetch(
proxy_pass http://fetch;
)
# 類似案例:
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
閱讀原文:原文鏈接
該文章在 2025/7/21 10:24:50 編輯過