美文网首页Nginx
Nginx Location详细使用(学习笔记十六)

Nginx Location详细使用(学习笔记十六)

作者: SkTj | 来源:发表于2018-05-17 12:16 被阅读130次

    location 实例练习

    Nginx 的语法形式是: location [=|~|~*|^~|@] /uri/ { … } ,意思是可以以“ = ”或“ ~* ”或“ ~ ”或“ ^~ ”或“ @ ”符号为前缀,当然也可以没有前缀(因为 [A] 是表示可选的 A ; A|B 表示 A 和 B 选一个),紧接着是 /uri/ ,再接着是{…} 指令块,整个意思是对于满足这样条件的 /uri/ 适用指令块 {…} 的指令。

    上述各种 location 可分两大类,分别是:“普通 location ”,官方英文说法是 location using   literal strings 和“正则 location ”,英文说法是 location usingregular expressions。其中“普通 location ”是以“ = ”或“ ^~ ”为前缀或者没有任何前缀的 /uri/ ;“正则 location ”是以“ ~ ”或“ ~* ”为前缀的 /uri/ 。

    那么,当我们在一个 server 上下文编写了多个 location 的时候, Nginx 对于一个 HTTP 请求,是如何匹配到一个 location 做处理呢?用一句话简单概括 Nginx 的 location 匹配规则是:“正则 location ”让步“普通 location”的严格精确匹配结果;但覆盖“普通 location ”的最大前缀匹配结果。理解这句话,我想通过下面的实例来说明。

    #1 先普通 location ,再正则 location

    周边不少童鞋告诉我, nginx 是“先匹配正则 location 再匹配普通 location ”,其实这是一个误区, nginx 其实是“先匹配普通 location ,再匹配正则 location ”,但是普通 location 的匹配结果又分两种:一种是“严格精确匹配”,官方英文说法是“ exact match ”;另一种是“最大前缀匹配”,官方英文说法是“ Literal strings match the beginning portion of the query – the most specific match will be used. ”。我们做个实验:

    例题 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/

    403 Forbidden

    403 Forbidden


    nginx/1.1.0

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

    Welcome to nginx!

    Welcome to nginx!

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

    404 Not Found

    404 Not Found


    nginx/1.1.0

    [root@web108 ~]#

    测试结果如下:

    URI 请求HTTP 响应

    curl http://localhost:9090/403 Forbidden

    curl http://localhost:9090/index.htmlWelcome to nginx!

    curl http://localhost:9090/index_notfound.html404 Not Found

    curlhttp://localhost:9090/的结果是“ 403 Forbidden ”,说明被匹配到“ location / {..deny all;} ”了,原因很简单HTTP 请求 GET / 被“严格精确”匹配到了普通 location / {} ,则会停止搜索正则 location ;

    curlhttp://localhost:9090/index.html结果是“ Welcome to nginx! ”,说明没有被“ location / {…deny all;} ”匹配,否则会 403 Forbidden ,但 /index.html 的确也是以“ / ”开头的,只不过此时的普通 location / 的匹配结果是“最大前缀”匹配,所以 Nginx 会继续搜索正则 location , location ~ \.html$ 表达了以 .html 结尾的都 allow all; 于是接着就访问到了实际存在的 index.html 页面。

    curlhttp://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

    403 Forbidden

    403 Forbidden


    nginx/1.1.0

    [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

    404 Not Found

    404 Not Found


    nginx/1.1.0

    [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 Forbidden403 Forbidden

    curl http://localhost:9090/index.htmlWelcome to nginx!403 Forbidden

    curl http://localhost:9090/index_notfound.html404 Not Found403 Forbidden

    curl http://localhost:9090/exact/match.html404 Not Found404 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 Forbidden403 Forbidden

    curl http://localhost:9090/index.htmlWelcome to nginx!Welcome to nginx!

    curl http://localhost:9090/index_notfound.html404 Not Found404 Not Found

    curl http://localhost:9090/exact/match.html404 Not Found404 Not Found

    curl http://localhost:9090/test.jsp403 Forbidden404 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.html404 Not Found404 Not Found

    curl http://localhost:9090/prefix/regextest.html404 Not Found403 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.1配置 3.2

    curl http://localhost:9090/prefix/t.html403 Forbidden403 Forbidden

    curl http://localhost:9090/prefix/mid/t.html404 Not Found404 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 404http://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

    302 Found

    Found

    The document has moved here.

    [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

    302 Found

    Found

    The document has moved here.

    [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

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

    。。。。

    显示,的确百度这个页面是存在的。

    [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

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

    。。。

    当 curl http://localhost:9090/duty/ -i 时, nginx 没找到对应的页面,于是 error_page = @fallback ,把请求代理到 baidu.com 。注意这里的 error_page = @fallback 不是靠重定向实现的,而是所说的“ internally redirected (forward )”

    =:完全匹配才行

    ^~:匹配就行,但是不再进行匹配

    空: 匹配后,还会匹配

    ~      正则

    ~*    正则

    Nginx 允许用户定义 Location block ,并指定一个匹配模式(pattern)匹配特定的 URI。除了简单的字符串(比如文件系统路径),还允许使用更为复杂的匹配模式(pattern)。

    Location block 的基本语法形式是:

        location [=|~|~*|^~|@] pattern { ... }

    [=|~|~*|^~|@] 被称作 location modifier ,这会定义 Nginx 如何去匹配其后的 pattern ,以及该 pattern 的最基本的属性(简单字符串或正则表达式)。

    ------- 关于 location modifier -------

    1. =

    这会完全匹配指定的 pattern ,且这里的 pattern 被限制成简单的字符串,也就是说这里不能使用正则表达式。

    Example:

    server {

        server_name website.com;

        location = /abcd {

        […]

        }

    }

    匹配情况:

        http://website.com/abcd        # 正好完全匹配

        http://website.com/ABCD        # 如果运行 Nginx server 的系统本身对大小写不敏感,比如 Windows ,那么也匹配

        http://website.com/abcd?param1¶m2    # 忽略查询串参数(query string arguments),这里就是 /abcd 后面的 ?param1¶m2

        http://website.com/abcd/    # 不匹配,因为末尾存在反斜杠(trailing slash),Nginx 不认为这种情况是完全匹配

        http://website.com/abcde    # 不匹配,因为不是完全匹配

    2. (None)

    可以不写 location modifier ,Nginx 仍然能去匹配 pattern 。这种情况下,匹配那些以指定的 patern 开头的 URI,注意这里的 URI 只能是普通字符串,不能使用正则表达式。

    Example:

    server {

        server_name website.com;

        location /abcd {

        […]

        }

    }

    匹配情况:

        http://website.com/abcd        # 正好完全匹配

        http://website.com/ABCD        # 如果运行 Nginx server 的系统本身对大小写不敏感,比如 Windows ,那么也匹配

        http://website.com/abcd?param1¶m2    # 忽略查询串参数(query string arguments),这里就是 /abcd 后面的 ?param1¶m2

        http://website.com/abcd/    # 末尾存在反斜杠(trailing slash)也属于匹配范围内

        http://website.com/abcde    # 仍然匹配,因为 URI 是以 pattern 开头的

    3. ~

    这个 location modifier 对大小写敏感,且 pattern 须是正则表达式

    Example:

    server {

        server_name website.com;

        location ~ ^/abcd$ {

        […]

        }

    }

    匹配情况:

        http://website.com/abcd        # 完全匹配

        http://website.com/ABCD        # 不匹配,~ 对大小写是敏感的

        http://website.com/abcd?param1¶m2    # 忽略查询串参数(query string arguments),这里就是 /abcd 后面的 ?param1¶m2

        http://website.com/abcd/    # 不匹配,因为末尾存在反斜杠(trailing slash),并不匹配正则表达式 ^/abcd$

        http://website.com/abcde    # 不匹配正则表达式 ^/abcd$

    注意:对于一些对大小写不敏感的系统,比如 Windows ,~ 和 ~* 都是不起作用的,这主要是操作系统的原因。

    4. ~*

    与 ~ 类似,但这个 location modifier 不区分大小写,pattern 须是正则表达式

    Example:

    server {

        server_name website.com;

        location ~* ^/abcd$ {

        […]

        }

    }

    匹配情况:

        http://website.com/abcd        # 完全匹配

        http://website.com/ABCD        # 匹配,这就是它不区分大小写的特性

        http://website.com/abcd?param1¶m2    # 忽略查询串参数(query string arguments),这里就是 /abcd 后面的 ?param1¶m2

        http://website.com/abcd/    # 不匹配,因为末尾存在反斜杠(trailing slash),并不匹配正则表达式 ^/abcd$

        http://website.com/abcde    # 不匹配正则表达式 ^/abcd$

    5. ^~

    匹配情况类似 2. (None) 的情况,以指定匹配模式开头的 URI 被匹配,不同的是,一旦匹配成功,那么 Nginx 就停止去寻找其他的 Location 块进行匹配了(与 Location 匹配顺序有关)

    6. @

    用于定义一个 Location 块,且该块不能被外部 Client 所访问,只能被 Nginx 内部配置指令所访问,比如 try_files or error_page

    ------- 搜索顺序以及生效优先级 -------

    因为可以定义多个 Location 块,每个 Location 块可以有各自的 pattern 。因此就需要明白(不管是 Nginx 还是你),当 Nginx 收到一个请求时,它是如何去匹配 URI 并找到合适的 Location 的。

    要注意的是,写在配置文件中每个 Server 块中的 Location 块的次序是不重要的,Nginx 会按 location modifier 的优先级来依次用 URI 去匹配 pattern ,顺序如下:

        1. =

        2. (None)    如果 pattern 完全匹配 URI(不是只匹配 URI 的头部)

        3. ^~

        4. ~ 或 ~*

        5. (None)    pattern 匹配 URI 的头部

    http://www.cnblogs.com/lidabo/p/4169394.html

    http://www.cnblogs.com/lidabo/p/4169396.html

    相关文章

      网友评论

        本文标题:Nginx Location详细使用(学习笔记十六)

        本文链接:https://www.haomeiwen.com/subject/lelbdftx.html