Nginx localtion匹配規則


mark:2016年05月25日13:20:54 (存手打,拒絕轉載)

一、location分為 普通location 和 正則location

 

只有帶有 "~" 或者"~*"前綴的屬於 正則location

“=”,“^~ ”和“@ ” 和無任何前綴的(例如只有  "location /name") 屬於普通location

 

二、location匹配順序

 

當一個請求發送到nginx的時候,匹配到了server模塊后,就會進到我們的location模塊。request 先匹配普通location然后在匹配正則location,當然這里也可以在普通location 這里終止匹配結果,但是需要一定的條件。

這里我們講一下普通location和普通location 的匹配順序,普通location 和普通location的匹配規則為最大前綴匹配。當然也可以理解為精確匹配。這里我們舉一個官網文檔上的例子來說明。

 Let’s illustrate the above by an example:

    location = / {
        [ configuration A ]
    }

    location / {
        [ configuration B ]
    }

    location /documents/ {
        [ configuration C ]
    }

    location ^~ /images/ {
        [ configuration D ]
    }

    location ~* \.(gif|jpg|jpeg)$ {
        [ configuration E ]
    }

 The “/” request will match configuration A, the “/index.html” request will match configuration B, the “/documents/document.html” request will match configuration C,

the “/images/1.gif” request will match configuration D, and the “/documents/1.jpg” request will match configuration E.

這里我以A、B、C、D、E來標記這些location,當然E屬於正則location。我們來解釋一下每個的匹配結果。 再次mark一下:by:V。

request=/ 時,因為所有的請求都會有一個前綴“/”所以 ”location / {。。。}“ 是一定可以匹配到的,但是還有一個 "= /" 這個“=”的意思為,最大前綴匹配,而request=/ 所以會匹配到A,有的同學想問那么B也是嚴格匹配,但是我想說"/"的優先級沒有"= /"高。

request=/images/1.git時,和上面一個一樣,因為A為嚴格匹配,所以這個請求不會匹配到A,但是B為普通前綴匹配,所以會匹配到B,但是這個時候並不是最精確的匹配(還有一個隱式匹配,下面再說),所以還會查看其他普通location的規則,當然C匹配不到,這個時候D也屬於普通location ,那么D 這個是什么意思,“^~”  ^代表非, ~代表正則的意思,意思就是不需要繼續搜索正則location,但是要匹配這項,需要是最大前綴匹配,這里最大前綴可能有很多人理解模糊,這里我說明一下。例如requst=/1/2/1.html 這里的最大前綴就是/1/2/,所以這個request會匹配到D然后終止搜索正則location。

 

request=/documents/1.jpg,匹配到BC,后因為這個時候沒有終止匹配符號"="或"^~"或“隱式”匹配,所以還會繼續匹配正則location。而正則location的匹配順序是按照排名順序來匹配的。所以就會匹配到以jpg結尾的正則location。

有人也許也有疑問, "^~" 和 "= "的區別是什么, 他們共同點都是可以終止搜索正則location,不同點是一個是最大前綴匹配,一個是精確匹配。

 

總結一下上述的問題點:

1,普通location和順序無關、正則location按照順序來匹配

2、“=”或者"^~" 會終止正則搜索,但是不會終止普通location搜索。

3、匹配優先級最高的當然是精確匹配。

4、只要匹配到了正則location(不管是什么匹配,也就是說不需要最精確的匹配結果),就會終止繼續往下搜索。

5、只有帶有 "~" 或者"~*"前綴的屬於 正則location。其余的都是普通location。

6、@ 這個用的不多,想了解的可以自行百度,有需求的可以在下方提問也行。

 

===================以下例子為轉載。當然很正確。有疑問請留言================

為了加深理解,我這里加入幾個例子。

借鑒其他博客的例子。 nginx基礎配置如下

                                                                          

例題 1 :假設 nginx 的配置如下

server {

       listen       9090;

       server_name  localhost;

                  location / {

           root   html;

           index  index.html index.htm;

           deny all;

       }

       location ~ \.html$ {

           allow all;

       }

}

附錄 nginx 的目錄結構是: nginx->html->index.html

上述配置的意思是: location / {… deny all;} 普通 location 以“ / ”開始的 URI 請求(注意任何 HTTP 請求都必然以“/ ”開始,所以“ / ”的意思是所有的 請求都能被匹配上),都拒絕訪問; location ~\.html$ {allow all;} 正則 location以 .html 結尾的 URI 請求,都允許訪問。

 

測試結果:

[root@web108 ~]# curl http://localhost:9090/

<html>

<head><title>403 Forbidden</title></head>

<body bgcolor=”white”>

<center><h1>403 Forbidden</h1></center>

<hr><center>nginx/1.1.0</center>

</body>

</html>

[root@web108 ~]# curl http://localhost:9090/index.html

<html>

<head>

<title>Welcome to nginx!</title>

</head>

<body bgcolor=”white” text=”black”>

<center><h1>Welcome to nginx!</h1></center>

</body>

</html>

[root@web108 ~]# curl http://localhost:9090/index_notfound.html

<html>

<head><title>404 Not Found</title></head>

<body bgcolor=”white”>

<center><h1>404 Not Found</h1></center>

<hr><center>nginx/1.1.0</center>

</body>

</html>

[root@web108 ~]#

 

測試結果如下:

URI 請求 HTTP 響應
curl http://localhost:9090/ 403 Forbidden
curl http://localhost:9090/index.html Welcome to nginx!
curl http://localhost:9090/index_notfound.html 404 Not Found

 

curl http://localhost:9090/ 的結果是“ 403 Forbidden ”,說明被匹配到“ location / {..deny all;} ”了,原因很簡單HTTP 請求 GET / 被“嚴格精確”匹配到了普通 location / {} ,則會停止搜索正則 location ;

curl http://localhost:9090/index.html 結 果是“ Welcome to nginx! ”,說明沒有被“ location / {…deny all;} ”匹配,否則會 403 Forbidden ,但 /index.html 的確也是以“ / ”開頭的,只不過此時的普通 location / 的匹配結果是“最大前綴”匹配,所以 Nginx 會繼續搜索正則 location , location ~ \.html$ 表達了以 .html 結尾的都 allow all; 於是接着就訪問到了實際存在的 index.html 頁面。

curl http://localhost:9090/index_notfound.html   同 樣的道理先匹配 location / {} ,但屬於“普通 location 的最大前綴匹配”,於是后面被“正則 location ” location ~ \.html$ {} 覆蓋了,最終 allow all ; 但的確目錄下不存在index_notfound.html 頁面,於是 404 Not Found 。

 

如果此時我們訪問 http://localhost:9090/index.txt 會 是什么結果呢?顯然是 deny all ;因為先匹配上了 location / {..deny all;} 盡管屬於“普通 location ”的最大前綴匹配結果,繼續搜索正則 location ,但是 /index.txt 不是 以 .html結尾的,正則 location 失敗,最終采納普通 location 的最大前綴匹配結果,於是 deny all 了。

[root@web108 ~]# curl http://localhost:9090/index.txt

<html>

<head><title>403 Forbidden</title></head>

<body bgcolor=”white”>

<center><h1>403 Forbidden</h1></center>

<hr><center>nginx/1.1.0</center>

</body>

</html>

[root@web108 ~]#

#2 普通 location 的“隱式”嚴格匹配

例題 2 :我們在例題 1 的基礎上增加精確配置

 

server {

       listen       9090;

       server_name  localhost;

                  location /exact/match.html {

           allow all;

       }

                  location / {

           root   html;

           index  index.html index.htm;

           deny all;

       }

       location ~ \.html$ {

           allow all;

       }

}

 

測試請求:

[root@web108 ~]# curl http://localhost:9090/exact/match.html

<html>

<head><title>404 Not Found</title></head>

<body bgcolor=”white”>

<center><h1>404 Not Found</h1></center>

<hr><center>nginx/1.1.0</center>

</body>

</html>

[root@web108 ~]#

 

結果進一步驗證了“普通 location ”的“嚴格精確”匹配會終止對正則 location 的搜索。這里我們小結下“普 通 location”與“正則 location ”的匹配規則:先匹配普通 location ,再匹配正則 location ,但是如果普 通 location 的匹配結果恰好是“嚴格精確( exact match )”的,則 nginx 不再嘗試后面的正則 location ;如果普通 location 的匹配結果是“最大前綴”,則正 則 location 的匹配覆蓋普通 location 的匹配。也就是前面說的“正則 location 讓步普通location 的嚴格精確匹配 結果,但覆蓋普通 location 的最大前綴匹配結果”。

#3 普通 location 的“顯式”嚴格匹配和“ ^~ ” 前綴

上面我們演示的普通 location 都是不加任何前綴的,其實普通 location 也可以加前綴:“ ^~ ”和“ = ”。其中 “ ^~”的意思是“非正則,不需要繼續正則匹配”,也就是通常我們的普通 location ,還會繼續搜索正則 location (恰好嚴格精確匹 配除外),但是 nginx 很人性化允許配置人員告訴 nginx 某條普通 location ,無論最大前綴匹配,還是嚴格精確匹配都終止繼續搜索 正則 location ;而“ = ”則表達的是普通 location 不允許“最大前綴”匹配結果,必須嚴格等於,嚴格精確匹配。

 

例題 3 :“ ^~ ”前綴的使用

server {

       listen       9090;

       server_name  localhost;

                  location /exact/match.html {

           allow all;

       }

                 location ^~ / {

           root   html;

           index  index.html index.htm;

           deny all;

       }

       location ~ \.html$ {

           allow all;

       }

}

 

把例題 2 中的 location / {} 修改成 location ^~ / {} ,再看看測試結果:

URI 請求 修改前 修改后
curl http://localhost:9090/ 403 Forbidden 403 Forbidden
curl http://localhost:9090/index.html Welcome to nginx! 403 Forbidden
curl http://localhost:9090/index_notfound.html 404 Not Found 403 Forbidden
curl http://localhost:9090/exact/match.html 404 Not Found 404 Not Found

 

除了 GET /exact/match.html 是 404 Not Found ,其余都是 403 Forbidden ,原因很簡單所有請求都是以“ / ”開頭,所以所有請求都能匹配上“ / ”普通 location ,但普 通 location 的匹配原則是“最大前綴”,所以只有/exact/match.html 匹配到 location /exact/match.html {allow all;} ,其余都 location ^~ / {deny all;} 並終止正則搜索。

 

例題 4 :“ = ”前綴的使用

server {

       listen       9090;

       server_name  localhost;

                  location /exact/match.html {

           allow all;

       }

                 location = / {

           root   html;

           index  index.html index.htm;

           deny all;

       }

       location ~ \.html$ {

           allow all;

       }

}

例題 4 相對例題 2 把 location / {} 修改成了 location = / {} ,再次測試結果:

URI 請求 修改前 修改后
curl http://localhost:9090/ 403 Forbidden 403 Forbidden
curl http://localhost:9090/index.html Welcome to nginx! Welcome to nginx!
curl http://localhost:9090/index_notfound.html 404 Not Found 404 Not Found
curl http://localhost:9090/exact/match.html 404 Not Found 404 Not Found
curl http://localhost:9090/test.jsp 403 Forbidden 404 Not Found

 

最能說明問題的測試是 GET /test.jsp ,實際上 /test.jsp 沒有匹配正則 location ( location ~\.html$ ),也沒有匹配 location = / {} ,如果按照 location / {} 的話,會“最大前綴”匹配到普通 location / {} ,結果是 deny all 。

#4 正則 location 與編輯順序

location 的指令與編輯順序無關,這句話不全對。對於普通 location 指令,匹配規則是:最大前綴匹配(與順序無關),如果恰好是 嚴格精確匹配結果或者加有前綴“ ^~ ”或“ = ”(符號“ = ”只能嚴格匹配,不能前綴匹配),則停止搜索正則 location ;但對於正 則 location 的匹配規則是:按編輯順序逐個匹配(與順序有關),只要匹配上,就立即停止后面的搜索。

 

配置 3.1

server {

       listen       9090;

       server_name  localhost;

 

       location ~ \.html$ {

           allow all; 

       }  

 

       location ~ ^/prefix/.*\.html$ {

           deny all;  

       }  

 

}

配置 3.2

server {

       listen       9090;

       server_name  localhost;

 

      

       location ~ ^/prefix/.*\.html$ {

           deny all;  

       }  

                 

                  location ~ \.html$ {

           allow all; 

       } 

 

}

 

測試結果:

URI 請求 配置 3.1 配置 3.2
curl http://localhost:9090/regextest.html 404 Not Found 404 Not Found
curl http://localhost:9090/prefix/regextest.html 404 Not Found 403 Forbidden

 

解釋:

Location ~ ^/prefix/.*\.html$ {deny all;} 表示正則 location 對於以 /prefix/ 開頭, .html 結尾的所有 URI 請求,都拒絕訪 問;   location ~\.html${allow all;} 表示正則 location 對於以 .html 結尾的 URI 請求,都允許訪問。 實際上,prefix 的是 ~\.html$ 的 子集。

在“配置 3.1 ”下,兩個請求都匹配上 location ~\.html$ {allow all;} ,並且停止后面的搜索,於是都允許訪問, 404 Not Found ;在“配置 3.2 ”下, /regextest.html 無法匹配 prefix ,於是繼續搜索 ~\.html$ ,允許訪問,於 是 404 Not Found ;然而 /prefix/regextest.html 匹配到 prefix ,於是 deny all , 403 Forbidden 。

 

配置 3.3

server {

       listen       9090;

       server_name  localhost;

 

       location  /prefix/ {

               deny all;  

       }  

          

       location  /prefix/mid/ {

               allow all; 

       }  

 

}

配置 3.4

server {

       listen       9090;

       server_name  localhost;

 

     

       location  /prefix/mid/ {

               allow all; 

       }  

                  location  /prefix/ {

               deny all;  

       }  

}

測試結果:

URI 請求 配置 3.3 配置 3.4
curl http://localhost:9090/prefix/t.html 403 Forbidden 403 Forbidden
curl http://localhost:9090/prefix/mid/t.html 404 Not Found 404 Not Found

 

測試結果表明:普通 location 的匹配規則是“最大前綴”匹配,而且與編輯順序無關。

 

#5 “@” 前綴 Named Location 使用

REFER:  http://wiki.nginx.org/HttpCoreModule#error_page

假設配置如下:

server {

       listen       9090;

       server_name  localhost;

 

        location  / {

           root   html;

           index  index.html index.htm;

           allow all;

       }

       #error_page 404 http://www.baidu.com # 直接這樣是不允許的

       error_page 404 = @fallback;

 

       location @fallback {

           proxy_pass http://www.baidu.com;

       }

}

 

上述配置文件的意思是:如果請求的 URI 存在,則本 nginx 返回對應的頁面;如果不存在,則把請求代理到baidu.com 上去做個彌 補(注: nginx 當發現 URI 對應的頁面不存在, HTTP_StatusCode 會是 404 ,此時error_page 404 指令能捕獲它)。

 

測試一:

[root@web108 ~]# curl http://localhost:9090/nofound.html -i

HTTP/1.1 302 Found

Server: nginx/1.1.0

Date: Sat, 06 Aug 2011 08:17:21 GMT

Content-Type: text/html; charset=iso-8859-1

Location: http://localhost:9090/search/error.html

Connection: keep-alive

Cache-Control: max-age=86400

Expires: Sun, 07 Aug 2011 08:17:21 GMT

Content-Length: 222

 

<!DOCTYPE HTML PUBLIC “-//IETF//DTD HTML 2.0//EN”>

<html><head>

<title>302 Found</title>

</head><body>

<h1>Found</h1>

<p>The document has moved <a href=”http://www.baidu.com/search/error.html”>here</a>.</p>

</body></html>

[root@web108 ~]#

 

當我們 GET /nofound.html 發送給本 nginx , nginx 找不到對應的頁面,於是 error_page 404 = @fallback ,請求被代理到 http://www.baidu.com ,於是 nginx 給 http://www.baidu.com 發送了 GET /nofound.html ,但/nofound.html 頁面在百度也不存在,百度 302 跳轉到錯誤頁。

直接訪問 http://www.baidu.com/nofound.html 結果:

[root@web108 ~]# curl http://www.baidu.com/nofound.html -i

HTTP/1.1 302 Found

Date: Sat, 06 Aug 2011 08:20:05 GMT

Server: Apache

Location: http://www.baidu.com/search/error.html

Cache-Control: max-age=86400

Expires: Sun, 07 Aug 2011 08:20:05 GMT

Content-Length: 222

Connection: Keep-Alive

Content-Type: text/html; charset=iso-8859-1

 

<!DOCTYPE HTML PUBLIC “-//IETF//DTD HTML 2.0//EN”>

<html><head>

<title>302 Found</title>

</head><body>

<h1>Found</h1>

<p>The document has moved <a href=”http://www.baidu.com/search/error.html”>here</a>.</p>

</body></html>

[root@web108 ~]#

 

測試二:訪問一個 nginx 不存在,但 baidu 存在的頁面

[root@web108 ~]# curl http://www.baidu.com/duty/ -i

HTTP/1.1 200 OK

Date: Sat, 06 Aug 2011 08:21:56 GMT

Server: Apache

P3P: CP=” OTI DSP COR IVA OUR IND COM ”

P3P: CP=” OTI DSP COR IVA OUR IND COM ”

Set-Cookie: BAIDUID=5C5D2B2FD083737A0C88CA7075A6601A:FG=1; expires=Sun, 05-Aug-12 08:21:56 GMT; max-age=31536000; path=/; domain=.baidu.com; version=1

Set-Cookie: BAIDUID=5C5D2B2FD083737A2337F78F909CCB90:FG=1; expires=Sun, 05-Aug-12 08:21:56 GMT; max-age=31536000; path=/; domain=.baidu.com; version=1

Last-Modified: Wed, 05 Jan 2011 06:44:53 GMT

ETag: “d66-49913b8efe340″

Accept-Ranges: bytes

Content-Length: 3430

Cache-Control: max-age=86400

Expires: Sun, 07 Aug 2011 08:21:56 GMT

Vary: Accept-Encoding,User-Agent

Connection: Keep-Alive

Content-Type: text/html

 

<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN”

“http://www.w3.org/TR/html4/loose.dtd”>

。。。。

</body>

</html>

顯示,的確百度這個頁面是存在的。

[root@web108 ~]# curl http://localhost:9090/duty/ -i

HTTP/1.1 200 OK

Server: nginx/1.1.0

Date: Sat, 06 Aug 2011 08:23:23 GMT

Content-Type: text/html

Connection: keep-alive

P3P: CP=” OTI DSP COR IVA OUR IND COM ”

P3P: CP=” OTI DSP COR IVA OUR IND COM ”

Set-Cookie: BAIDUID=8FEF0A3A2C31D277DCB4CC5F80B7F457:FG=1; expires=Sun, 05-Aug-12 08:23:23 GMT; max-age=31536000; path=/; domain=.baidu.com; version=1

Set-Cookie: BAIDUID=8FEF0A3A2C31D277B1F87691AFFD7440:FG=1; expires=Sun, 05-Aug-12 08:23:23 GMT; max-age=31536000; path=/; domain=.baidu.com; version=1

Last-Modified: Wed, 05 Jan 2011 06:44:53 GMT

ETag: “d66-49913b8efe340″

Accept-Ranges: bytes

Content-Length: 3430

Cache-Control: max-age=86400

Expires: Sun, 07 Aug 2011 08:23:23 GMT

Vary: Accept-Encoding,User-Agent

 

<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN”

“http://www.w3.org/TR/html4/loose.dtd”>

<html>

。。。

</body>

</html>

當 curl http://localhost:9090/duty/ -i 時, nginx 沒找到對應的頁面,於是 error_page = @fallback ,把請求代理到 baidu.com 。注意這里的 error_page = @fallback 不是靠重定向實現的,而是所說的“ internally redirected (forward )”。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM