nginx的location正则匹配必须用~或~*显式声明,且严格按“= → ^~ → 按序正则 → /”优先级执行,一旦命中即终止匹配;多数404/502问题源于匹配顺序误判,如^~规则会跳过后续所有正则。

直接说结论:Nginx 的 location 正则匹配不是“随便写正则就能生效”,必须用 ~ 或 ~* 显式声明,且匹配顺序和优先级远比写对正则本身更关键——多数 502/404/跳转错乱问题,根源都在匹配逻辑被误判。
location ~ 和 ~* 的区别与选型
区分大小写与否,直接影响静态资源或 API 路径是否命中:
-
~ \.php$:只匹配/api.php,不匹配/API.PHP -
~* \.php$:两者都匹配,适合前端打包后大小写混杂的资源(如某些构建工具生成的main.JS) - 注意:
~*性能略低(需做 case-fold),但对用户友好;若确定路径全小写(如标准 REST API),用~更稳妥 - 别写
~ *.js——*在正则里是量词,不是 shell 通配符;正确写法是~* \.js$
为什么写了正则却没生效?匹配顺序陷阱
Nginx 不是“找最像的”,而是严格按固定顺序扫描并**一旦命中就停止**:
- 先扫所有普通 location(
=、^~、无前缀),取最长前缀匹配(例如/admin/api会优先进入location /admin/api/而非location /admin/) - 再按配置文件中出现的**物理顺序**逐条试正则,第一个匹配即终止(哪怕后面有更精确的正则)
- 关键点:
^~ /static/这类前缀匹配一旦成功,**后续所有正则(包括~* \.(css|js)$)全被跳过** - 常见错误:把
location ~* \.js$放在location ^~ /static/上面,结果 /static/app.js 被前缀规则截走,正则根本没机会执行
实际常用正则写法与避坑点
真实配置中,这些写法高频出现,但细节决定成败:
- 匹配带版本号的静态资源:
location ~* ^/static/v\d+\.\d+\.\d+/(.+)\.(css|js|png|jpg)$——注意^锚定开头,避免/user/static/v1.2.3/main.js被误抓 - 排除某类路径:
location ~* ^/api/(?!v2/).*\.json$——用负向先行断言(NGINX 1.11.5+ 支持),但低版本不兼容,慎用 - 转义点号:
\.必须写,.js会匹配任意单字符 +js(比如/a-js或/xjs) - 结尾锚定:
$强烈建议加上,否则~* \.js会匹配/script.js.map或/jsbundle.jsx - 路径中含空格或特殊字符:NGINX 解析时**不对 URI 解码**,所以
/images/%20logo.png必须用location ~* /images/.*logo\.png$,不能写成/images/ logo.png
调试正则是否命中:不要靠猜
光看配置很难验证,得靠日志和响应头定位:
- 临时加
return 200 "matched: /static/";到目标location块,curl 直接看返回 - 开启
error_log /var/log/nginx/error.log notice;,NGINX 启动时会报“using configuration”并列出所有location加载顺序 - 用
nginx -t只能校验语法,**不能验证匹配逻辑**;真正要测,必须发请求 + 查 access log 中的$request_uri和$host - 注意:浏览器地址栏输入的 URL 会被自动编码(如空格变
%20),而location规则是对解码后的路径匹配 —— 实际行为以$request_uri变量为准
最常被忽略的点:正则 location 的性能开销是普通 location 的数倍,且顺序不可逆。与其堆砌复杂正则,不如用 ^~ 做前缀隔离 + 简单正则收尾,既清晰又可控。











