先给结论:优先级从高到低
Nginx 的 location 匹配不是“按配置顺序从上到下”,而是按类型分层。记住这条顺序,80% 的困惑就没了:
- = 精确匹配,命中即返回,最高优先级
- ^~ 前缀匹配,命中后不再检查正则
- ~ 和 ~* 正则匹配,按配置中出现的顺序,第一个命中的生效
- 普通前缀匹配(无修饰符),取最长匹配
容易忽略的一点:普通前缀匹配命中后,Nginx 还会继续尝试正则;只有 ^~ 和 = 会“截断”后续检查。所以“最长前缀”不一定最终生效,正则可能后来居上。
一个例子看清匹配过程
假设配置如下:
location = /api { return 200 "exact"; }
location ^~ /static/ { return 200 "prefix-noregex"; }
location ~ .php$ { return 200 "regex-php"; }
location /images/ { return 200 "prefix-images"; }
location / { return 200 "root"; }
请求 /api 命中精确匹配,直接返回。请求 /static/a.php 命中 ^~,即使后面有 ~ .php$ 也不会再检查。请求 /images/x.php 先记住最长前缀 /images/,但随后正则 ~ .php$ 命中,最终走正则。请求 /images/a.png 正则不命中,回落到前缀 /images/。
常见坑一:以为写了最长前缀就一定生效
这是最常见的误解。只要存在能匹配上的正则 location,普通前缀就会被覆盖。解决办法有两个:一是给前缀加 ^~,二是把正则写得更精确。排查时可以用 nginx -T 看完整配置,确认没有隐藏的正则规则(比如 include 进来的通用 ~ .(js|css)$)。
常见坑二:正则顺序与嵌套 location
正则按配置文件中的书写顺序匹配,第一个命中就停,不是“最精确优先”。所以把更具体的正则写在前面,例如先写 ~ ^/api/v2/ 再写 ~ ^/api/。另外,嵌套 location 里的正则只在外层前缀命中后才参与,不要指望外层正则去匹配内层路径。
常见坑三:rewrite 后的 location 与 try_files
在 location 内执行 rewrite ... last; 会重新走一遍 location 匹配,可能落入另一个 location,形成循环时 Nginx 会报 “rewrite or internal redirection cycle”。用 try_files $uri $uri/ /index.html; 做单页应用回退时,要确保最后的回退目标本身不会再触发同一段逻辑,否则同样会循环。调试阶段可在 server 块临时加 error_log /var/log/nginx/debug.log debug;,观察实际命中的 location。
最后提醒:改完配置先 nginx -t 校验,再 nginx -s reload 平滑生效,不要直接 restart 生产环境。

