nginx 的 location匹配原则

2019-05-18  本文已影响0人  OOM_Killer

location 的匹配是find_conf这个模块提供的功能,这个模块是十分重要的一个阶段,在nginx的11个处理顺序上, rewrite -> find_config -> rewrite 。 find_conf 是加在两个rewrite 操作之间的,而find_conf的作用呢,一句话概况就是,这个url 到底由哪个location匹配并进行进一步操作。

nginx 的 rewrite 模块的链接 https://www.jianshu.com/p/74bf196b63cc

find_conf 的 最重要的一个指令当然就是location了,除此之外还有一个merge_slashes指令。

find_conf

这里主要的还是location的匹配了,这也是最难的问题,有人会误以为这是rewrite模块提供的功能,其实不然,这是find_conf提供的。
下面提供一个location的匹配顺序,其实,也正如下图所示,请区分
^~ 、= 、正则的关系。被 ^~ 匹配上了,就不再做正则匹配了。
在nginx中有一个 binary tree存放所有的 前缀字符串。


location 匹配顺序.png

有如下的nginx配置。

        location ~ /Test/$ {
                return 200 'first regular expressions match!\n';
        }
        location ~* /Test1/(\w+)$ {
                return 200 'longest regular expressions match!\n';
        }
        location ^~ /Test1/ {
                return 200 'stop regular expressions match!\n';
        }
        location /Test1/Test2 {
                return 200 'longest prefix string match!\n';
        }
        location /Test1 {
                return 200 'prefix string match\n';
        }
        location = /Test1 {
                return 200 'exact match!';
        }

如果访问的是如下链接都会怎么样返回呢?

/Test1
/Tesr1/
/Test1/Test2
/Test1/Test2
/test1/Test2

下面一个一个分析

# curl -H"Host:location.example.wjx" http://127.0.0.1/Test1
exact match!
# curl -H"Host:location.example.wjx" http://127.0.0.1/Test1/
stop regular expressions match!
# curl -H"Host:location.example.wjx" http://127.0.0.1/Test1/Test2
longest regular expressions match!
# curl -H"Host:location.example.wjx" http://127.0.0.1/Test1/Test2/
longest prefix string match!

结合反向代理proxy_pass

其实在日常的操作中都会遇到怎么将一个请求反向代理到后端的场景,而事实上,nginx的最大的用处就是做反向代理的用途。
但是 location 加/ 和 proxy加 / ,很多人高不清楚。
其实 proxy加根,表示是以绝对路径访问,就是说,location中的东西一律不带到后面去。
如 我访问 http://proxy.example.wjx/v1/freeins
如下配置

        location  /v1/ {
                proxy_pass http://server1_backend;
        }

后端得到的请求是

"GET /v1/freeins HTTP/1.0"

如果后端不想要 /v1 怎么办呢。proxy_pass 后加/ 就可以了。

        location  /v1/ {
                proxy_pass http://server1_backend/;
        }

后端得到的请求是

"GET /freeins HTTP/1.0"

但是!!!
location 如果使用的正则表达式的话,在proxy_pass 后面就不能再加 路径了。如下配置

        location ~ ^/v1/ {
                proxy_pass http://server1_backend/;
        }

如果reload的话,直接会报错。

nginx: [emerg] "proxy_pass" cannot have URI part in location given by regular expression, or inside named location,
 or inside "if" statement, or inside "limit_except" block in /usr/local/openresty/nginx/conf/../site_enables/proxy_pass.conf:31

这是因为nginx是以模块化的方式构建的,每个配置块都是由各个模块在各个阶段读取的。所以请记住,proxy_pass在以下情况下,指令中不能有URI :

实战

那好吧,假设已有如下配置,它被反向代理到server1 的backend。那我想将 /v1/freeins 开头的反代到 server2 中且 不能将v1 带到后端去,这该怎么办呢?

        location ~ ^/v1/ {
                proxy_pass http://server1_backend;
        }

解决
其实使用 ^~ 就可以了。
看看配置

        location ~ ^/v1/ {
                proxy_pass http://server1_backend;
        }
        location ^~ /v1/freeins {
                proxy_pass http://server2_backend/freeins;
        }

# curl -H"Host:proxy.loki.wjx" http://127.0.0.1/v1/freeins/getProduct?id=13232453
后端接收到的请求。
"GET /freeins/getProduct?id=13232453 HTTP/1.0"
上一篇下一篇

猜你喜欢

热点阅读