zoukankan      html  css  js  c++  java
  • 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 )”。

  • 相关阅读:
    BEC listen and translation exercise 44
    中译英12
    BEC listen and translation exercise 43
    中译英11
    BEC listen and translation exercise 42
    中译英10
    BEC listen and translation exercise 41
    中译英9
    BEC listen and translation exercise 40
    中译英8
  • 原文地址:https://www.cnblogs.com/shiyiwen/p/5526978.html
Copyright © 2011-2022 走看看