我有一份配置:
server {
listen 12080;
server_name abc.com;
access_log /var/log/nginx/test.access.log;
error_log /var/log/nginx/test.error.log;
location ~* \.png$ {
return 402;
}
location / {
return 400;
}
location /static/js/css/ {
return 405;
}
location ^~ /static/ {
return 401;
}
location ^~ /static/js/ {
return 404;
}
location = /static/abc.png {
return 403;
}
}
为什么/static/js/css/4.png 返回 402 ,而/static/js/4.png 返回 404 ?正则的优先级不是很低吗,第一个为什么是正则生效,并且/static/js/css6/4.png 又是 404 ,第一个地址和第 3 个地址为什么会出现不同的匹配生效?
1
sundong 341 天前
`=` 开头表示精确匹配 ,如 A 中只匹配根目录结尾的请求,后面不能带任何字符串。
`^~` 开头表示 uri 以某个常规字符串开头,不是正则匹配 `~` 开头表示区分大小写的正则匹配; `~*` 开头表示不区分大小写的正则匹配 `/` 通用匹配, 如果没有其它匹配,任何请求都会匹配到 |
2
Hopetree OP @sundong /static/js/css/4.png 按照^~优先不是应该匹配到 404 那条吗,怎么会到 402 的正则,然后/static/js/css6/4.png 又匹配的是正则,这两个的区别是啥导致的?
|
3
Huelse 341 天前
= > ^~ > ~/~* > 空格
|
4
dzdh 341 天前
https://github.com/nginx/nginx/blob/master/src/http/ngx_http_core_module.c#L3087
不懂 c ,但是看个大概齐 先判断 location 参数? 3 个优先?三个参数的时候,优先级是 =、^~、~、~*、 else 不是三个参数,优先级:=、^~、~(如果还有后续参数*?) |
6
dzdh 341 天前
|
9
deepzz 341 天前 1
可以看看匹配的规则: https://deepzz.com/post/how-to-write-nginx-server.html#toc_6
1. 精确匹配 =,如果匹配成功,搜索停止 2. 前缀匹配,最长位置匹配,如果该匹配具有 ^~,搜索停止 3. 正则匹配,按配置文件中定义的顺序进行匹配。 4. 如果第 3 条规则产生匹配的话,结果被使用。否则,使用第 2 条规则的结果。 |
10
xiaooloong 341 天前
理论上来说 9 楼说的对,但试了一下
```bash root@ubuntu:/usr/local/openresty/nginx/conf# curl -I localhost:12080/foobar HTTP/1.1 400 Bad Request Server: openresty/1.21.4.2 Date: Thu, 21 Dec 2023 06:25:54 GMT Content-Type: text/html Content-Length: 163 Connection: close root@ubuntu:/usr/local/openresty/nginx/conf# curl -I localhost:12080/static/js/css/4.png HTTP/1.1 402 Payment Required Server: openresty/1.21.4.2 Date: Thu, 21 Dec 2023 06:26:04 GMT Content-Type: text/html Content-Length: 173 Connection: keep-alive root@ubuntu:/usr/local/openresty/nginx/conf# curl -I localhost:12080/static/js/4.png HTTP/1.1 404 Not Found Server: openresty/1.21.4.2 Date: Thu, 21 Dec 2023 06:26:16 GMT Content-Type: text/html Content-Length: 159 Connection: keep-alive root@ubuntu:/usr/local/openresty/nginx/conf# curl -I localhost:12080/static/js/css6/4.png HTTP/1.1 404 Not Found Server: openresty/1.21.4.2 Date: Thu, 21 Dec 2023 06:26:40 GMT Content-Type: text/html Content-Length: 159 Connection: keep-alive ``` 确实有这个问题 |
11
momooc 341 天前 via Android
不懂,这样看确实,可能有什么点忽略了,坐等大佬发现问题
|
12
coderzhangsan 341 天前
@deepzz 2.前缀匹配,最长位置匹配,如果该匹配具有 ^~,搜索停止; 如何理解这个最长位置?
|
13
google2020 341 天前
人生苦短,我选 openresty
|
14
rockyliang 341 天前 2
@coderzhangsan #12 ,其实就是匹配相同的子字符串,看哪个子字符串最长
比如有三个 location : A:/a B: /a/b C:/a/b/c 对于字符串 /a/b/c/d ,A 、B 、C 三个都能匹配到,但 C 是最长的,所以最终会采用 C 这个 location |
15
Hopetree OP @deepzz 其实之前我也看了匹配规则的,就是因为看了然后验证发现不对,比如按照你这个逻辑,无法解释为什么/static/js/css/4.png 返回 402 ,/static/js/css6/4.png 又是 404 这两个明明都是同时匹配到了前缀和正则,为什么结果不同
|
16
Hopetree OP 给大家提供一个网站可以很快的验证匹配规则,不用自己去配置 nginx ,网站地址: https://nginx.viraptor.info/
|
17
Hopetree OP @rockyliang 按照这个说法,/static/js/css/4.png 已经匹配到了前缀/static/js/,为什么没有停止搜索,最终是正则生效了?而/static/js/css6/4.png 又是前缀/static/js/来生效的?这个说不通
|
18
liangxiangdong 341 天前
我之前遇到过这个问题,就是正则和前缀匹配都满足的情况,正则优先。除非前缀匹配有修饰符,不过具体什么修饰符可以走到 405 我还真没研究过。https://docs.nginx.com/nginx/admin-guide/web-server/web-server/ /some/path/document.html 下面有一段话。
|
19
rockyliang 341 天前 5
@Hopetree #17
因为 405 、401 、404 这三个都属于前缀模式匹配。/static/js/css/4.png 同时匹配到了这三个前缀模式,当同时匹配到多个前缀模式时,需要按最长匹配规则进行选取,即最终会命中 405 。 而 405 没有阻止继续匹配正则,所以会继续匹配正则模式,而正则模式就是 402 那个,所以会返回 402 |
20
wscgogo 341 天前
@rockyliang 666
|
21
TommySung 341 天前
是没问题的!
毫无疑问,匹配原则是精确匹配,即最大程度能匹配上 在这一原则下,最长匹配就是判断标准 1. 首先 /static/js/css/4.png 会匹配到 1 ,保留 然后,/static/js/css/4.png 会匹配到 3 ,而 4 ,5 ,6 都无法与其”匹敌“,因为 3 和他们比较匹配度最高 而 1 因为是正则匹配,且能匹配到结尾扩展名,也属于匹配度最高,换句话说你使用/static/js/css/4.jpg 则会匹配到 3 在此情况下,1 和 3 匹配度都最高,那么正则优先,所以 /static/js/css/4.png 会匹配到 1 2. /static/js/4.png 最高匹配度会匹配到 1 ,3 ,5 ,但 5 的优先级明显高于 1 和 3 ,所以返回 5 3. /static/js/css6/4.png 同上 容易错误的地方如: location /static/js/css/ location ^~ /static/js/ 如果你的 uri 包括/static/js/css/ ,那么虽然 location ^~ /static/js/ 也能匹配上,并且优先级高于 location /static/js/css/ 但 location /static/js/css/ 属于最精确匹配或最高匹配度,最后就会被选中 匹配度最高或最精准匹配 是 大于 所谓优先级的 |
22
godall 341 天前
@rockyliang 大师
|
23
Leon406 341 天前
|
25
omgr 341 天前
官方文档写的很清楚了,细读下就好了。
> If the longest matching prefix location has the “^~” modifier then regular expressions are not checked 你给的测试网址也说明了这个问题,prefix 匹配实际上分两种,如果最长匹配命中的是 ^~ 类型的,就会直接返回,如果是普通的,同时有正则的话,就会按写的顺序依次正则匹配,正则匹配到了就用正则了。 你的例子中: /static/js/css/4.png 最长前缀匹配到了 /static/js/css/ 会继续检查正则 /static/js/4.png 最长前缀匹配到了 ^~ /static/js/ 直接返回 |
26
omgr 341 天前
跟 405 状态码没有关系的
|
27
Hopetree OP 经过上面 21 和 25 楼的解析,我画了一个流程图,不知道按照验证好像是对的,请各位大佬看看,是不是这样
![image]( https://github.com/Hopetree/izone/assets/30201215/fa522cfe-9e5a-453b-b2f6-2f89b9250596) |
28
Hopetree OP 重新编辑一下:经过上面 21 和 25 楼的解析,我画了一个流程图,按照验证好像是对的,请各位大佬看看,是不是这样
![image]( https://github.com/Hopetree/izone/assets/30201215/fa522cfe-9e5a-453b-b2f6-2f89b9250596) |
29
Hopetree OP |
30
Hopetree OP 我为这个讨论的结果写了一篇学习总结文章,有兴趣的可以看看,https://tendcode.com/subject/article/nginx-location/,如果文章中表述有错误的,欢迎指出纠正
|