一文读懂nginx的location匹配规则
一、location的指令分为两种匹配模式 :
- 普通字符串匹配
- 正则匹配
二、普通匹配包含三种格式:
修饰符 | 参考示例 | 说明 |
---|---|---|
无 | location /hello/world | 前缀匹配,不支持正则 |
= | location = /hello/world | 又叫精确匹配,不支持正则,匹配后既终止正则匹配又终止普通匹配 |
^~ | location ^~ /hello/world | 前缀匹配,不支持正则 ,匹配后不再进行正则匹配 |
三、正则匹配包含两种格式:
修饰符 | 参考示例 | 说明 |
---|---|---|
~ | location ~ \.jpg$ | 区分大小写的正则匹配,是包含匹配,而非前缀匹配 |
~* | location ~* \.jpg$ | 不区分大小写的正则匹配,是包含匹配,而非前缀匹配 |
四、location匹配顺序
五、关于location匹配的一些误区
1、 location 的匹配顺序是“先匹配正则,再匹配普通”。
矫正: location 的匹配顺序其实是“先匹配普通,再“考虑”匹配正则”。注意这里的“考虑”是“可能”的意思,也就是说匹配完“普通 location ”后,有的时候需要继续匹配“正则 location ”,有的时候则不需要继续匹配“正则 location ”。两种情况下,不需要继续匹配正则 location :
( 1 )当普通 location 前面指定了“ ^~ ”,特别告诉 Nginx 本条普通 location 一旦匹配上,则不需要继续正则匹配;
( 2 )当普通location 恰好严格匹配上,不是最大前缀匹配,则不再继续匹配正则。
2、 location 的执行逻辑跟 location 的编辑顺序无关。
矫正:这句话不全对,“普通 location ”的匹配规则是“最大前缀”,因此“普通 location ”的确与 location 编辑顺序无关;但是“正则 location ”的匹配规则是“顺序匹配,且只要匹配到第一个就停止后面的匹配”
总结一句话:“正则 location 匹配让步普通 location 的严格精确匹配结果;但覆盖普通 location 的最大前缀匹配结果”
六、举个栗子
此处我用的是openresty版本的nginx,因此可以直接使用echo指令。如果是原生nginx,要使用echo指令的话,则需要自行编译安装echo-nginx-module,参考:https://github.com/openresty/echo-nginx-module#installation
server {
listen 80;
server_name localhost;
location / {
echo "first";
}
location ^~ /hello {
echo "111111-normal";
}
location /hello/world {
echo "222222-normal";
}
location ~ /hello/world {
echo "333333-regex";
}
}
访问http://127.0.0.1/hello/world
的结果如下:
分析
在这个例子中,先进行普通匹配,按照最长匹配的原则,匹配到第三个location,然后这里的修饰符是非"="或"^~",则会继续向下进行正则匹配,匹配到第四个location。
我们对上面的栗子进行稍加修改,将第三个和第四个location调换下顺序,且将location /hello/world
修改为location ^~ /hello/world
如下:
server {
listen 80;
server_name localhost;
location / {
echo "first";
}
location ^~ /hello {
echo "111111-normal";
}
location ~ /hello/world {
echo "333333-regex";
}
location ^~ /hello/world {
echo "222222-normal";
}
}
这时候再访问http://127.0.0.1/hello/world
的结果如下:
由此可以说明,匹配的顺序是“先普通,再“考虑”正则”,而"="或"^~"这两个修饰符会终止“考虑”正则。看到这里,是不是就清晰了很多呢。