Nginx 的 location 匹配优先级是怎样的?
Nginx location 匹配顺序完整规则:精确匹配 = > 前缀匹配 ^~ > 正则 ~ / ~* > 普通前缀;最长前缀优先、正则按定义顺序;附决策流程示例与 FAQ。
记忆口诀:= 精确匹配最高 → ^~ 前缀阻断 → ~/~* 正则(按出现顺序)→ 普通前缀(最长者胜,但可被正则反超)。 掌握这条链,90% 的"配置没按预期走"都能解释。
完整匹配流程
Nginx 拿到 URI 后按这个顺序决策:
1. = /exact 精确匹配 → 命中即用,流程结束 ← 最高优先级
2. 普通前缀匹配 找出"最长"前缀(含 ^~ 变体),先记下
├─ 若最长前缀带 ^~ → 直接使用,不再看正则
3. ~ 和 ~* 正则 按配置文件中出现的顺序逐个尝试
├─ 任一命中 → 使用它,流程结束(覆盖第 2 步结果)
4. 都不中 → 用第 2 步记下的最长前缀
四种修饰符对照
| 写法 | 类型 | 优先级 | 说明 |
|---|---|---|---|
location = /a |
精确 | 1(最高) | URI 必须一字不差 |
location ^~ /a |
前缀阻断 | 2 | 命中后不再尝试正则 |
location ~ \.php$ |
正则(区分大小写) | 3 | 按文件中出现顺序匹配 |
location ~* \.(jpg|png)$ |
正则(不区分大小写) | 3 | 同上 |
location /a |
普通前缀 | 4 | 最长前缀胜出,但可能被正则抢走 |
实例推演
location / { ... } # ① 普通前缀
location /images/ { ... } # ② 普通前缀(更长)
location ^~ /static/ { ... } # ③ 前缀阻断
location ~ \.css$ { ... } # ④ 正则
location = /favicon.ico { ... } # ⑤ 精确
/favicon.ico→ ⑤ 精确匹配,直接结束。/static/logo.png→ ③ 是最长前缀且带^~,不看正则 → 走 ③。/images/style.css→ 最长前缀是 ②(无^~)→ 继续看正则 → ④\.css$命中 → 走 ④。/images/cat.jpg→ ② 是最长前缀,正则不命中 → 走 ②。
三个高频坑
- 正则抢前缀:以为
location /api/会处理/api/x.php,结果被~ \.php$截胡。想保住前缀优先级,用^~。 - 正则顺序敏感:多个正则按文件顺序匹配,不是"最具体优先"——把更精确的正则放前面。
- 嵌套 location:匹配到的 location 内部还可以再嵌套(比如 PHP location 里再分静态/动态),规则同样适用。
观测云对照
location 配置错了,流量会被静默路由到错误的后端或返回 404——从 Nginx 本身看一切"正常"。把访问日志接入观测云,按 URI 前缀聚合状态码和 upstream 分布,"某路径突然大量 404/502"实时可见;变更配置后对照前后流量分布,是否误伤立刻有数。
常见问题(FAQ)
Q:alias 和 root 在不同 location 里行为一样吗?
A:不一样,这正是 location 相关的经典坑:root 会把完整 URI 拼在目录后,alias 只替换匹配前缀。混用时仔细核对路径拼接结果。
Q:location 里能再写 location 吗?
A:可以嵌套,外层命中后在内层继续匹配。常见于 /api/ 内再细分 /api/v1/。
Q:怎么验证我的 location 到底命中了哪个?
A:最直接:在每个 location 里加不同的 add_header X-Location "block-A";,用 curl -I 看返回头。或临时开 debug 日志看匹配过程。