Nginx location 匹配順序整理


Nginx location模塊整理

具體的Nginx安裝就不在這里描述了,這里只是為了對location的描述

Nginx環境

a. 查看當前系統cat /etc/redhat-release

[root@nginx /]# cat /etc/redhat-release

CentOS release 6.7 (Final)

[root@nginx /]#

b. 查看系統內核uname –r

[root@nginx /]# uname -r

2.6.32-573.el6.x86_64

[root@nginx /]#

c. 安裝的Nginx版本,/appliation/nginx/sbin/nginx -V

[root@nginx sbin]# ./nginx -V

nginx version: nginx/1.6.2

built by gcc 4.4.7 20120313 (Red Hat 4.4.7-16) (GCC)

TLS SNI support enabled

configure arguments: --user=nginx --group=nginx --prefix=/application/nginx1.6.2 --with-http_stub_status_module --with-http_ssl_module

[root@nginx sbin]#

 

location模塊

Nginx location

location 指令的作用是根據用戶請求的URI來執行不同的應用,URI就是根據用戶請求到的網址URL進行匹配,匹配成功了進行相關的操作。

location語法

下面是官網的語法結構:

Syntax:    location [ = | ~ | ~* | ^~ ] uri { ... }

location @name { ... }

Default:   —

Context:   server, location

官網解釋翻譯和理解

下面會結合官網原文進行解釋,以下英文部分均從官網摘抄:

http://nginx.org/en/docs/http/ngx_http_core_module.html#location

(翻譯的不好勿噴)

Sets configuration depending on a request URI.

根據請求的URI進行配置

URI 變量是待匹配的請求字符串,

A location can either be defined by a prefix string, or by a regular expression.

Regular expressions are specified with the preceding “~*” modifier (for case-insensitive matching), or the “~” modifier (for case-sensitive matching)

一個location可以用prefix string(前綴字符串)定義,也可以通過regular expression(正則表達式來定義)

通俗的說也就是:我們可以通過使用不同的前綴,表達不同的含義,對於不同的前綴可以分為兩大類:普通location和正則location

符號:”~”表示uri包含正則,並且區分大小寫

符號:“~*”表示uri包含正則,但不區分大小寫

注意:如果你的uri用正則,則你的正則前面必須添加~或者~*,之前我在這里存在誤區,以為可以不加~或者~*

To find location matching a given request, nginx first checks locations defined using the prefix strings (prefix locations). Among them, the location with the longest matching prefix is selected and remembered. Then regular expressions are checked, in the order of their appearance in the configuration file. The search of regular expressions terminates on the first match, and the corresponding configuration is used. If no match with a regular expression is found then the configuration of the prefix location remembered earlier is used.

Nginx服務器會首先會檢查多個location中是否有普通的uri匹配,如果有多個匹配,會先記住匹配度最高的那個。然后再檢查正則匹配,這里切記正則匹配是有順序的,從上到下依次匹配,一旦匹配成功,則結束檢查,並就會使用這個location塊處理此請求。如果正則匹配全部失敗,就會使用剛才記錄普通uri匹配度最高的那個location塊處理此請求。

If the longest matching prefix location has the “^~” modifier then regular expressions are not checked.

當普通匹配的最長前綴匹配有符號“^~”的時候,就不會在匹配正則

直接使用當前匹配的這個location塊處理此請求

Also, using the “=” modifier it is possible to define an exact match of URI and location. If an exact match is found, the search terminates. For example, if a “/” request happens frequently, defining “location = /” will speed up the processing of these requests, as search terminates right after the first comparison. Such a location cannot obviously contain nested locations.

使用符號“=”修飾符可以定義一個精確匹配的URI和位置,如果找到了一個精確的匹配,則搜索終止,例如,如果一個”/”請求頻繁發生,定義“location =/”將加快這些請求的處理,一旦精確匹配只有就結束,這樣的location顯然不能包含嵌套location

這里我們說一下location / {} 和location =/ {}的區別:

“location / {}”是普通的最大前綴匹配,任何的uri肯定是以“/”開頭,所以location / {} 可以說是默認匹配,當其他都不匹配了,則匹配默認匹配

根據上述官網內容進行總結

a. ”=”用於普通uri前,要求精確匹配,如果匹配成功,則停止搜索並用當前location處理此請求

b. ”~” 表示uri包含正則,並且區分大小寫

c. “~*”表示uri包含正則,但不區分大小寫

d. ”^~”表示在普通uri前要求Nginx服務器找到普通uri匹配度最高的那個location后,立即處理此請求,並不再進行正則匹配

e. ”^~”和“=”都可以阻止繼續匹配正則location兩者的區別:“^~”依然遵守最大前綴原則,然后“=”是需要嚴格匹配

關於location網上的一些誤解

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

這是一個錯誤的結論,從上面官網的文章中我們可以知道:

先匹配普通uri,然后記住匹配度最高的那個(官網原話:To find location matching a given request, nginx first checks locations defined using the prefix strings (prefix locations). Among them, the location with the longest matching prefix is selected and remembered.)然后匹配正則,如果正則匹配則結束查找,如果正則不匹配,則匹配之前普通匹配中匹配度最高的那個將執行該請求(官網原話:Then regular expressions are checked, in the order of their appearance in the configuration file. The search of regular expressions terminates on the first match, and the corresponding configuration is used. If no match with a regular expression is found then the configuration of the prefix location remembered earlier is used.)

所以:location 的匹配順序是“先匹配正則,再匹配普通” 這句話肯定是錯誤的,況且這里並沒有包含”^~”和“=”

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

這也是一種錯誤的理解,我們根據上述內容可以知道:

如果是普通uri 匹配,這個時候是沒有順序的,但是正則匹配則是有順序的,是從上到下依次匹配,一旦有匹配成功,則停止后面的匹配

 

那么順序到底是怎么匹配呢?

我畫了一個location匹配的邏輯圖便於理解匹配的順序規則

 

 

通過實驗來驗證出結果

對www.conf配置如下:

[root@nginx extra]# cat www.conf

    server {

        listen       80;

        server_name  www.zhaofan.com;

        access_log      logs/access_www.log;

        root    html/www;

        location / {

            return 401;

        }

        location = / {

            return 402;

        }

 

        location  /documents/ {

            return 403;

        }

        location  ^~ /images/ {

            return 404;

        }

        location ~* \.(gif|jpg|jpeg)$ {

            return 500;

        }

    }

[root@nginx extra]#

注意:

        location ~* \.(gif|jpg|jpeg)$ {

            return 500;

這個部分$前面不能有空格,否則會提示如下錯誤:

[root@nginx extra]# ../../sbin/nginx -s reload

nginx: [emerg] invalid location modifier "~*\.(gif|jpg|jpeg)" in /application/nginx1.6.2/conf/extra/www.conf:19

如果$后面沒有空格,則會提示如下錯誤:

[root@nginx extra]# ../../sbin/nginx -s reload

nginx: [emerg] directive "location" has no opening "{" in /application/nginx1.6.2/conf/extra/www.conf:23

這些都是細節問題,一定要注意

實驗一:登錄nginx網站,我這里的直接打開:http://192.168.8.105/

 

 

可以看出這里是精確匹配

        location = / {

            return 402;

        }

 

實驗二:打開http://192.168.8.105/aaa/

 

 

這里可以看出因為都不匹配,所以最后匹配了location / {}

        location / {

            return 401;

        }

 

實驗三:打開http://192.168.8.105/1.gif

 

 

這里可以看出是匹配了正則

        location ~* \.(gif|jpg|jpeg)$ {

            return 500;

        }

 

實驗四:打開http://192.168.8.105/aaa/1.gif

 

 

這里依然是匹配正則

        location ~* \.(gif|jpg|jpeg)$ {

            return 500;

        }

 

實驗五:打開http://192.168.8.105/images/1.gif

 

 

        location / {

            return 401;

        }

        location = / {

            return 402;

        }

 

        location  /document/ {

            return 403;

        }

        location  ^~ /images/ {

            return 404;

        }

        location ~* \.(gif|jpg|jpeg)$ {

            return 500;

        }

這里通過配置把實驗三和實驗四的對比就可以看出來因為普通匹配里有“^~”,並且匹配到了images,所以這個就是不進行正則匹配

        location  ^~ /images/ {

            return 404;

        }

實驗六:“^~”遵守最大前綴原則

配置如下:

        location / {

            return 401;

        }

        location = / {

            return 402;

        }

 

        location  = /document/ {

            return 403;

        }

        location  ^~ /images/ {

            return 404;

        }

        location   /images/1/ {

            return 501;

        }

        location ~* \.(gif|jpg|jpeg)$ {

            return 500;

        }

還是關注標紅的地方,這個時候我們登陸:http://192.168.1.19/images/

結果如下:

 

 

從這里可以看出匹配了:

        location  ^~ /images/ {

            return 404;

        }

但是如果我們登陸:http://192.168.1.19/images/1/

結果如下;

 

 

這里匹配了:

        location   /images/1/ {

            return 501;

        }

從這里我們可以看出“^~”遵守最大匹配原則。

實驗七:當最長匹配和精確匹配相同時

配置如下:

        location / {

            return 401;

        }

        location = / {

            return 402;

        }

 

        location  = /document/ {

            return 403;

        }

        location  ^~ /images/ {

            return 404;

        }

        location   /images/1/ {

            return 501;

        }

 

        location  =  /images/1/ {

            return 502;

        }

        location ~* \.(gif|jpg|jpeg)$ {

            return 500;

        }

登陸:http://192.168.1.19/images/1/

結果如下:

 

 

但是如果這個時候登陸:http://192.168.1.19/images/1/aaa/

結果如下:

 

 

從這里我們可以看出當精確匹配和最長匹配相同時,匹配的是精確匹配。

 

不在過多的做實驗,根據上面的邏輯圖應該可以解決碰到的問題了

 


免責聲明!

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



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