nginx location匹配不是按配置顺序,而是严格分三阶段:先精确匹配(=)立即终止;再选最长前缀(含^~和普通前缀);最后仅当无^~时才按序检查正则(~/~*)。

请求路径匹配不是“谁写在前面就用谁”,而是 Nginx 内部一套严格分阶段、可预测的决策流程。它不依赖配置顺序的巧合,而是按数学定义的优先级逐层筛选,最终确定唯一生效的 location 块。
匹配不是遍历,是分阶段筛选
Nginx 不会从上到下逐行扫描所有 location 并比对——那样太慢且不可控。它把匹配拆成三个明确阶段:
-
第一阶段:精确匹配(=) —— 只要 URI 完全一致,立刻命中并终止,不看其他规则。比如
location = /health只响应/health,不响应/health/或/healthz。 -
第二阶段:前缀匹配筛选 —— 找出所有能匹配当前 URI 开头的所有前缀规则(含
^~和无修饰符),从中选出最长的那个。例如请求/api/v2/users,location /api/v2/比location /api/更长,优先选前者。 -
第三阶段:正则兜底判断 —— 仅当第二阶段选出的前缀规则中没有 ^~ 修饰符时,才继续检查正则规则(
~或~*),按配置出现顺序取第一个命中项;一旦遇到^~,正则直接跳过。
斜杠和结尾符号影响实际匹配结果
路径末尾是否有斜杠,直接决定是否触发子路径截断,也影响能否真正匹配成功:
-
location /static会匹配/static、/static/、/static/css/main.css—— 它是“前缀”,不是“目录”。 -
location /static/更安全,只匹配以/static/开头的路径,排除/static这种歧义情况。 -
location = /login和location /login行为完全不同:=只认/login;后者还会匹配/login/a、/login?next=/home。
proxy_pass 的行为由 location + 写法共同决定
location 匹配只是第一步,真正转发时怎么拼接后端地址,取决于 proxy_pass 末尾有没有斜杠:
-
location /api/ { proxy_pass http://backend; }→ 请求/api/v1/user转发为http://backend/api/v1/user(原路径完整保留)。 -
location /api/ { proxy_pass http://backend/; }→ 同样请求变成http://backend/v1/user(自动去掉/api/前缀)。 - 若用正则匹配,如
location ~ ^/api/(.+)$,必须配合变量写法:proxy_pass http://backend/$1;,否则后端收不到子路径。
server 块先于 location 生效,但常被忽略
很多人调不通 location,其实问题出在更早一层:server 块根本没被选中。Nginx 是先选 server,再选 location:
- 监听套接字(listen)决定了哪些 server 块有资格参与匹配。比如只写了
listen 80,那 HTTPS 请求(443 端口)根本不会进这个 server。 - 域名匹配靠
server_name,但它是“筛选后排序择优”,不是简单字符串相等。多个 server 都监听 80,Nginx 会按server_name字符串长度、通配符、正则等规则打分,选最优者。 - SSL 场景下,SNI(Server Name Indication)决定哪个证书被加载,也影响 server 块选择——如果客户端没发 SNI,可能默认落到第一个 server,导致证书错配或 404。











