很多个人开发者在使用 Nginx 的时候,面对配置文件中最多的 location 块,大多数情况靠的是“复制粘贴大法”。
在从网络上抄来的配置里,你会看到无数个长得非常类似但又有着微妙符号区别的代码段:
有的是 location = /,有的是 location ~ \.php$,还有的干干脆脆就是一个 location /。
直到有一天,你要配置一个前后端分离的项目。前台的静态资源希望走普通的静态文件代理,而所有带有 /api/ 的接口请求必须转发给后面监听本地端口的 Java 或者是 Node 服务。这时你发现自己抄来的规则突然都不管用了。这其实是因为 Nginx 在面对 URL 进行路由分发时,内嵌了一套极度反直觉但是又异常精确的“选妃”优先级规则。
在 2024 年,别再瞎试符号了。
Nginx 的匹配核心:从四种符号开始
Nginx 在 server 块接收到了一个用户的 HTTP 请求(比如:https://example.com/api/v1/user),它会抽出后面的 URI 路径(/api/v1/user),然后按照以下四个主要符号匹配规则去逐个对号入座。
第一等公民:精准全等匹配 (=)
这和代码里的判断完全一致。
location = /login {
# 只要你的路径精确地等于 /login
# 多一个斜杠,多一个参数,都不行!
}
优先级:史上最高。一旦它命中,Nginx 立刻停止搜寻后面的任何规则。
第二等公民:长前缀特权匹配 (^~)
这就是这套规则里最玄学和容易误导人的符号(带个 ~ 但人家根本不是正则!)。
location ^~ /api/ {
# 只要你访问的是以 /api/ 开头的(比如 /api/v1, /api/auth...)
}
优先级:一旦有以它开头的匹配,停止寻找后面的正则。
第三等公民:正则表达式匹配(~ 大小写敏感 / ~* 大小写不敏感)
在所有的正则前缀里,~ 区分了 URL 的大小写,而加上星号 ~* 就忽略大小写了。
location ~* \.(jpg|jpeg|png)$ {
# 所有以这几个图片结尾的,哪怕你写成了 .PNG 一样命中
}
优先级:所有正则的匹配,会按照你配置文件里书写的上下顺序进行。排在越上面的,越早被选中。
卑微的平民:普通前缀字符串匹配(啥都不带)
location / {
# 万金油,只要是 / 开头(也就是所有请求)都会被捕捉到
}
优先级:最低层级。它是备胎中的备胎,别人都匹配不上的时候,才会轮到它出来兜底。
Nginx 选妃的终极顺口溜!
千万别去死记硬背枯燥的表格,记住这段话:
- 先在一堆带等号
=的贵族里找。找到了?直接结束,带走! - 找不到精准等号的,再在一堆
^~和普通字符串(啥都不带的)里找出匹配度最长的那一个。 - 找出最长的那个后:如果这个最长的是个带
^~的刺头,那么直接结束,跟刺头走! - 如果最长的是个普通平民(啥也不带的),对不起,先把它当成备胎候补留着。Nginx 还要去翻一翻正则牌子。
- 去看下正则
~或~*。按照文件从上到下的顺序,谁第一个能匹配上,就直接跟正则走! - 如果所有的正则都没一个匹配上的,没办法,只能回来牵走刚才的备胎平民。
真题实战:你能说出它走哪个吗?
如果配置文件是这样的:
location /api { ...规则 A }
location ^~ /api/user { ...规则 B }
location ~ /api/v1 { ...规则 C }
location = /api/v1 { ...规则 D }
用户访问了 http://domian.com/api/v1:
- 先看等号有没有刚好叫这个的?
- 有!规则 D 精准匹配。直接进 D 结束战斗。
如果你把这个优先级牢记心中,下一次调反向代理的坑,你一眼就能看出哪里截胡了,真正体会一把庖丁解牛的快感。