主题
07 · location 匹配规则 · Nginx 最绕的部分
生活类比:Nginx 的
location像机场分诊台 + VIP 优先通道 + 经济舱通道——同一个旅客可能符合好几个通道,但只能走一条。哪条优先?这就是这一章要讲清楚的事。
1. 一图看懂 5 种 location 修饰符
┌──────────────────────────────────────────────────────────────┐
│ = 精确匹配(最高优先级,命中即止) │
│ ^~ 前缀匹配(命中后不再去测正则) │
│ ~ 正则匹配(区分大小写) │
│ ~* 正则匹配(不区分大小写) │
│ 无前缀 普通前缀匹配(最长匹配胜出) │
└──────────────────────────────────────────────────────────────┘5 种修饰符的优先级(重要、必背):
① = ← 精确匹配,找到立即用
② ^~ + 最长前缀 ← 前缀匹配里"最长"的那个
③ ~ / ~* ← 正则按"配置文件出现顺序"找第一个匹配
④ 普通前缀(最长) ← 正则全没命中,回退到最长前缀
⑤ / ← 兜底一句话记忆:等于优先 → 长前缀阻断正则 → 正则按顺序 → 长前缀兜底 → / 全包。
2. 5 种修饰符 · 详细举例
2.1 = 精确匹配
nginx
location = / {
return 200 'home';
}
location = /favicon.ico {
access_log off;
expires 30d;
}只有 URL 完全等于 / 时才命中。命中之后直接结束所有匹配。
生活类比:你只接待"叫张三"的客户,不接待"张三丰"。
2.2 ^~ 前缀阻断正则
nginx
location ^~ /static/ {
root /var/www;
expires 1y;
}^~ 的特殊点:命中后 不再试正则。即使后面有匹配的正则规则,也不去尝试。
适合:希望某个前缀绝对走这条,避免被正则规则抢走。
2.3 ~ / ~* 正则匹配
nginx
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
}
location ~* \.(jpg|png|gif)$ {
expires 1y;
}| 修饰符 | 含义 |
|---|---|
~ | 区分大小写的正则 |
~* | 不区分大小写的正则 |
注意:
- 正则是按配置文件中出现的顺序找第一个匹配
- 第一个匹配上了就用它,后面的正则不再试
2.4 普通前缀(无修饰符)
nginx
location /api/ { ... }
location /api/v2/ { ... }普通前缀匹配按"最长前缀"原则。/api/v2/foo 会命中 /api/v2/,因为 /api/v2/ 比 /api/ 长。
但找到后会继续看正则,正则胜出会覆盖前缀匹配(除非用了 ^~)。
2.5 / 兜底
nginx
location / { ... }所有 URL 都会"匹配上" /,但优先级最低。所以它经常作为兜底,比如 SPA fallback:
nginx
location / {
try_files $uri $uri/ /index.html;
}3. 完整匹配流程图
请求来了
│
▼
┌──────────────────┐
│ 1. 找 = 精确匹配 │ ── 找到 ──► ✅ 用它,结束
└─────────┬────────┘
│ 没找到
▼
┌──────────────────┐
│ 2. 找最长前缀 │ ── 记下来(暂存)
│ (含 ^~ 和普通) │
└─────────┬────────┘
│
▼
暂存的前缀是 ^~ 吗?
│
┌─┴─┐
是 否
│ │
│ ▼
│ ┌──────────────────┐
│ │ 3. 顺序找正则 │
│ │ ~ / ~* │ ── 命中第一个 ──► ✅ 用它
│ └─────────┬────────┘
│ │ 全没命中
▼ ▼
✅ 用前缀,结束4. 经典面试题:下面 5 个 URL 各命中哪条?
配置:
nginx
server {
location = / { return 200 'A'; }
location ^~ /static/ { return 200 'B'; }
location ~* \.(png|jpg)$ { return 200 'C'; }
location / { return 200 'D'; }
location /api/ { return 200 'E'; }
}测试:
| URL | 答案 | 分析 |
|---|---|---|
/ | A | 精确匹配 = 命中,结束 |
/static/logo.png | B | ^~ /static/ 命中,阻断正则 |
/img/cat.png | C | 没命中 ^~,进入正则阶段,命中 ~* \.png$ |
/api/users | E | 最长前缀 /api/ 胜过 /,没正则匹配,用 /api/ |
/about | D | 没精确、没 ^~、没正则、最长前缀就是 / |
5. 实战:location 的"6 个常用模板"
下面这些可以直接复用到生产配置:
5.1 SPA 兜底
nginx
location / {
try_files $uri $uri/ /index.html;
}5.2 静态资源强缓存
nginx
location ~* \.(?:css|js|png|jpg|webp|svg|woff2?)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}5.3 API 反向代理
nginx
location /api/ {
proxy_pass http://api_backend/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}5.4 健康检查端点
nginx
location = /healthz {
access_log off;
return 200 'ok\n';
}5.5 favicon 单独处理
nginx
location = /favicon.ico {
access_log off;
log_not_found off;
expires 30d;
}5.6 拒绝隐藏文件
nginx
location ~ /\. {
deny all;
}6. try_files 深入 · location 内部的"路径接力"
nginx
location / {
try_files $uri $uri/ @fallback;
}
location @fallback {
proxy_pass http://backend;
}@name 是命名 location,只能内部跳转,不会被外部 URL 直接命中。
应用场景:先找静态文件,没有就转到后端动态生成。
7. rewrite vs return vs try_files
| 指令 | 用法 | 副作用 |
|---|---|---|
return | return 301 URL; | 直接结束,浏览器看到 30x |
rewrite | rewrite ^/old$ /new last; | 内部改 URL,可能再次匹配 location |
try_files | try_files $uri /index.html; | 找文件 → 没了就 fallback |
3 个常用 rewrite:
nginx
# 1. 301 永久跳转
return 301 https://$host$request_uri;
# 2. 去掉尾部斜杠
rewrite ^/(.*)/$ /$1 permanent;
# 3. URL 重写(不改浏览器地址栏)
rewrite ^/blog/(\d+)$ /article.php?id=$1 last;last vs break:
last:重写后重新走一遍 location 匹配break:重写后留在当前 location 继续执行
这是 Nginx 第二大让人秃头的点 ⚠️。新人记忆:90% 用
last,没毛病。
8. ⚠️ location 匹配 8 大坑
- 同时写了
/api/和/api→ 两者都匹配/api,但/api/不匹配/api。容易把流量分错。 - 加了
^~没生效 → 写成~^了,反了。^~是"前缀阻断",~^是"以...开头的正则"。 - 正则顺序写错 → 越具体的正则越要写在前面,否则被通配的吃掉。
location嵌套 → Nginx 允许内嵌但容易出 bug,强烈建议别嵌套。alias末尾斜杠 →location /a/配alias /var/www/b/——/a/末尾必有斜杠对应。- 正则带变量 →
location ~ /api/$arg_v/写法不合法;变量在 location 上不起作用。 if在 location 里 → 官方 wiki 标题 "If is evil"——除了return和rewrite几乎啥都不能写。能用try_files/map解决就别用if。try_files多个文件名都不存在 → 需要兜底参数(最后一个),否则报错。try_files $uri $uri/ =404或... /index.html。
9. 章末面试题速览
详见
qa.md第 20-22 题。
- Nginx location 5 种修饰符的优先级是? →
=>^~ +最长前缀>~ / ~*(顺序) > 普通前缀(最长)。 ^~和~区别? →^~是前缀且阻断正则;~是正则匹配。if为啥被官方说 "evil"? → 行为反直觉、容易死循环、嵌套混乱;优先用try_files和map替代。
10. 一句话总结
location 匹配 = 优先级排序 + 修饰符:精确 > 前缀阻断 > 正则按顺序 > 最长前缀 >
/兜底——配合"6 个常用模板",覆盖 95% 的真实场景。
下一章 → 08 · HTTPS 配置:让你的站点带上"小绿锁"。
🎬 可视化演示
下方 demo 给你一份预设的 Nginx 配置,输入任意 URL → 即时高亮"哪条 location 命中",并把整个匹配步骤一步步播给你看。
🎬 可视化演示
演示加载缓慢或样式异常?点此在新标签页打开 ↗