Nginx匹配規則練習

晴天哥發表於2018-11-07

開篇

 這篇文章主要是和Nginx之location 匹配規則詳解配套的練習的例子,可以在自己的電腦上測試驗證加深Nginx location匹配規則理解,對於例子中不懂的地方可以看看上一篇文章。

 Nginx的匹配規則順序是

  • 1、location 的匹配順序是“先匹配正則,再匹配普通”。

 矯正: location 的匹配順序其實是“先匹配普通,再匹配正則”。我這麼說,大家一定會反駁我,因為按“先匹配普通,再匹配正則”解釋不了大家平時習慣的按“先匹配正則,再匹配普通”的實踐經驗。這裡我只能暫時解釋下,造成這種誤解的原因是:正則匹配會覆蓋普通匹配(實際的規則,比這複雜,後面會詳細解釋)。

  • 2、location 的執行邏輯跟 location 的編輯順序無關。

 矯正:這句話不全對,“普通 location ”的匹配規則是“最大字首”,因此“普通 location ”的確與 location 編輯順序無關;但是“正則 location ”的匹配規則是“順序匹配,且只要匹配到第一個就停止後面的匹配”;“普通location ”與“正則 location ”之間的匹配順序是?先匹配普通 location ,再“考慮”匹配正則 location 。注意這裡的“考慮”是“可能”的意思,也就是說匹配完“普通 location ”後,有的時候需要繼續匹配“正則 location ”,有的時候則不需要繼續匹配“正則 location ”。兩種情況下,不需要繼續匹配正則 location :( 1 )當普通 location 前面指定了“ ^~ ”,特別告訴 Nginx 本條普通 location 一旦匹配上,則不需要繼續正則匹配;( 2 )當普通location 恰好嚴格匹配上,不是最大字首匹配,則不再繼續匹配正則。

  • 3、總結一句話: “正則 location 匹配讓步普通 location 的嚴格精確匹配結果;但覆蓋普通 location 的最大字首匹配結果”

練習一、先普通 location ,再正則 location

  • 1、nginx配置
    server {
        listen       8000;
        server_name  localhost;

        location / {
            root   html;
            index  index.html index.htm;
            deny all;
        }
        
        location ~ .html$ {
            root   html;
            allow all;
        }
    }

  • 2、測試結果
URI 請求 HTTP 響應
curl http://localhost:8000/ 403 Forbidden
curl http://localhost:8000/index.html Welcome to nginx!
curl http://localhost:8000/index_notfound.html 404 Not Found

  • 3、說明

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

  • curl http://localhost:8000/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:8000/index_notfound.html 同樣的道理先匹配 location / {} ,但屬於“普通 location 的最大字首匹配”,於是後面被“正則 location ” location ~ .html$ {} 覆蓋了,最終 allow all ; 但的確目錄下不存在index_notfound.html 頁面,於是 404 Not Found

練習二、普通 location 的“隱式”嚴格匹配

  • 1、Nginx配置
    server {
        listen       8000;
        server_name  localhost;
       
        location / {
            root   html;
            index  index.html index.htm;
            deny all;
        }

        location /exact/match.html {
            root   html;
            allow all;
        }
        
        location ~ .html$ {
            root   html;
            allow all;
        }
    }

  • 2、測試結果
URI 請求 HTTP 響應
curl http://localhost:8000/exact/match.html/ 404 Not Found

  • 3、說明

  • “普通 location ”的“嚴格精確”匹配會終止對正則 location 的搜尋

  • “普通location 與 正則location的匹配規則:先匹配普通location ,再匹配正則location,但是如果普通 location的匹配結果恰好是“嚴格精確( exact match )”的,則Nginx不再嘗試後面的正則location ;如果普通 location的匹配結果是“最大字首”,則正則location的匹配覆蓋普通location的匹配。也就是前面說的“正則 location讓步普通location 的嚴格精確匹配結果,但覆蓋普通location的最大字首匹配結果”。

練習三、普通 location 的“顯式”嚴格匹配和“ ^~ ” 字首

  • 1、Nginx配置
    server {
        listen       8000;
        server_name  localhost;
       
        location ^~ / {
            root   html;
            index  index.html index.htm;
            deny all;
        }

        location /exact/match.html {
            root   html;
            allow all;
        }
        
        location /exact {
            root   html;
            allow all;
        }

        location ~ .html$ {
            root   html;
            allow all;
        }
    }

  • 2、測試結果
URI 請求 HTTP 響應
curl http://localhost:8000/ 403 Forbidden
curl http://localhost:8000/index.html 403 Forbidden
curl http://localhost:8000/index_notfound.html 403 Forbidden
curl http://localhost:8000/exact/match.html 404 Not Found
curl http://localhost:8000/exact/test.html 404 Not Found

  • 3、說明

  • 前三個http請求都是 403 Forbidden ,原因很簡單所有請求都是以“ / ”開頭,所以所有請求都能匹配上“ / ”普通location, location ^~ / {deny all;} 並終止正則搜尋。

  • /exact/match.html的請求返回404 Not Found,是因為在普通location匹配規則當中,/exact/match.html 匹配到 location /exact/match.html {allow all;} 。

  • /exact/test.html的請求返回404 Not Found,是因為普通 location 的匹配原則是“最大字首”,匹配上普通location的規則/exact {allow all;}

  • 可以得出結論在匹配普通location和正則location的時候,如果普通location匹配的結果是不繼續匹配正則location,那麼匹配就到此結束了

練習四、“ = ”字首的使用

  • 1、Nginx配置
    server {
        listen       8000;
        server_name  localhost;
       
        location = / {
            root   html;
            index  index.html index.htm;
            deny all;
        }

        location /exact/match.html {
            root   html;
            allow all;
        }
        
        location ~ .html$ {
            
            root   html;
            allow all;
        }
    }

  • 2、測試結果
URI 請求 HTTP 響應
curl http://localhost:8000/ 403 Forbidden
curl http://localhost:8000/index.html Welcome to nginx!
curl http://localhost:8000/index_notfound.html 404 Not Found
curl http://localhost:8000/exact/match.html 404 Not Found

  • 3、說明

  • / 返回403 Forbidden是因為匹配了普通location規則location = / {deny all;}

  • /index.html 和 index_notfound.html 匹配了正則location規則 ~ .html$ {allow all;},前者有對應的html檔案返回Welcome to nginx!,後者沒找到返回404 Not Found。

  • /exact/match.html匹配普通location的/exact/match.html,因為沒有對應的html檔案所以返回404 Not Found。

  • 匹配原則仍然是先普通location後正則location,但是”=”修飾的普通location需要完全精準匹配,如果沒有完全匹配還會繼續遍歷正則location,上例中的 /index.html 和 /index_notfound.html因為沒有完全精準匹配/,所以繼續遍歷正則location的結果。

練習五、正則location與編輯順序

  • 1、Nginx配置
    規則一
    server {
        listen       8000;
        server_name  localhost;
       
        location ~ .html$ {    
            root   html;
            deny all;
        }
       
        location ~ /prefix/.*.html$ {  
            root   html;
            rewrite /prefix/(.*).html /$1.html;
            allow all;
        }        
    }

規則二

    server {
        listen       8000;
        server_name  localhost;
           
        location ~ /prefix/.*.html$ {  
            root   html;
            allow all;
        }        

        location ~ .html$ {    
            root html;
            rewrite /prefix/(.*).html /$1.html;
            deny all;
        }
    }

  • 2、測試結果
URI 請求 規則一 HTTP 響應 規則二 HTTP 響應
http://localhost:8000/prefix/index.html 403 Forbidden 404 Not Found
http://localhost:8000/index.html 403 Forbidden 403 Forbidden

  • 3、說明

  • ~ /prefix/.*.html$” 表示正則location對於以/prefix/開頭.html結尾的所有URI請求都允許訪問; location ~.html${deny all;} 表示正則location對於以.html結尾的URI請求都拒絕訪問。

  • 正則location的匹配是按照編輯的先後順序進行匹配,匹配後不再繼續遍歷剩餘的正則location。

練習六、普通location與編輯順序

  • 1、Nginx配置
    server {
        listen       8000;
        server_name  localhost;

        location /prefix/ { 
            root   html;
            allow all;
        }   
        
        location /prefix/mid/ { 
            root   html;
            deny all;
        }
    }

  • 2、測試結果
URI 請求 HTTP 響應
http://localhost:8000/prefix/mid/index.html 403 Forbidden
http://localhost:8000/prefix/index.html 404 Not Found

  • 3、說明

  • 普通location /prefix/mid/匹配會拒絕請求,普通location /prefix/匹配會接受請求。

  • 普通 location 的匹配規則是“最大字首”匹配,而且與編輯順序無關。

參考文章

Nginx之location 匹配規則詳解


相關文章