我有一份配置:
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 2023-12-21 12:48:42 +08:00
`=` 开头表示精确匹配 ,如 A 中只匹配根目录结尾的请求,后面不能带任何字符串。
`^~` 开头表示 uri 以某个常规字符串开头,不是正则匹配 `~` 开头表示区分大小写的正则匹配; `~*` 开头表示不区分大小写的正则匹配 `/` 通用匹配, 如果没有其它匹配,任何请求都会匹配到 |
2
Hopetree OP @sundong /static/js/css/4.png 按照^~优先不是应该匹配到 404 那条吗,怎么会到 402 的正则,然后/static/js/css6/4.png 又匹配的是正则,这两个的区别是啥导致的?
|
3
Huelse 2023-12-21 12:54:36 +08:00
= > ^~ > ~/~* > 空格
|
4
dzdh 2023-12-21 12:57:35 +08:00
https://github.com/nginx/nginx/blob/master/src/http/ngx_http_core_module.c#L3087
不懂 c ,但是看个大概齐 先判断 location 参数? 3 个优先?三个参数的时候,优先级是 =、^~、~、~*、 else 不是三个参数,优先级:=、^~、~(如果还有后续参数*?) |
5
Hopetree OP @Huelse 按照这个顺序的话,/static/js/css/4.png 不是应该先被 404 那个规则命中吗,怎么最终的结果是 402 ?
|
6
dzdh 2023-12-21 13:05:46 +08:00
|
9
deepzz 2023-12-21 13:21:22 +08:00 1
可以看看匹配的规则: https://deepzz.com/post/how-to-write-nginx-server.html#toc_6
1. 精确匹配 =,如果匹配成功,搜索停止 2. 前缀匹配,最长位置匹配,如果该匹配具有 ^~,搜索停止 3. 正则匹配,按配置文件中定义的顺序进行匹配。 4. 如果第 3 条规则产生匹配的话,结果被使用。否则,使用第 2 条规则的结果。 |
10
xiaooloong 2023-12-21 14:27:52 +08:00
理论上来说 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 2023-12-21 14:51:36 +08:00 via Android
不懂,这样看确实,可能有什么点忽略了,坐等大佬发现问题
|
12
coderzhangsan 2023-12-21 14:57:55 +08:00
@deepzz 2.前缀匹配,最长位置匹配,如果该匹配具有 ^~,搜索停止; 如何理解这个最长位置?
|
13
google2020 2023-12-21 14:58:21 +08:00
人生苦短,我选 openresty
|
14
rockyliang 2023-12-21 15:06:21 +08:00 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 2023-12-21 15:27:24 +08:00
我之前遇到过这个问题,就是正则和前缀匹配都满足的情况,正则优先。除非前缀匹配有修饰符,不过具体什么修饰符可以走到 405 我还真没研究过。https://docs.nginx.com/nginx/admin-guide/web-server/web-server/ /some/path/document.html 下面有一段话。
|
19
rockyliang 2023-12-21 15:27:25 +08:00 5
@Hopetree #17
因为 405 、401 、404 这三个都属于前缀模式匹配。/static/js/css/4.png 同时匹配到了这三个前缀模式,当同时匹配到多个前缀模式时,需要按最长匹配规则进行选取,即最终会命中 405 。 而 405 没有阻止继续匹配正则,所以会继续匹配正则模式,而正则模式就是 402 那个,所以会返回 402 |
20
wscgogo 2023-12-21 15:57:20 +08:00
@rockyliang 666
|
21
TommySung 2023-12-21 16:58:03 +08:00
是没问题的!
毫无疑问,匹配原则是精确匹配,即最大程度能匹配上 在这一原则下,最长匹配就是判断标准 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 2023-12-21 17:00:27 +08:00
@rockyliang 大师
|
23
Leon406 2023-12-21 20:48:16 +08:00
|
24
Hopetree OP @Leon406 怎么解释这个图,有相关文章说明的吗,有的话麻烦推一下,我看了好多文章,但是把我测试的配置和请求结果拿去验证发现没有有个经得住验证的
|
25
omgr 2023-12-22 09:16:58 +08:00
官方文档写的很清楚了,细读下就好了。
> 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 2023-12-22 09:17:33 +08:00
跟 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/,如果文章中表述有错误的,欢迎指出纠正
|