Nginx 里 location 与 try_files 的一个常见坑
把前端打包产物丢到 Nginx 后面,首页能开、点进去也能跳,一刷新就 404。
或者反过来:路由都正常了,但 /assets/ 下的 css、js 全变成首页的 HTML。
这两个现象经常是同一个原因——try_files 的兜底写得太宽。
先理清 location 的匹配顺序
Nginx 不是按配置文件里的书写顺序从上到下试的。实际顺序大致是:
=精确匹配,命中就停^~前缀匹配,命中就停,不再看正则- 正则
~/~*,按书写顺序,第一个命中就用它 - 普通前缀匹配,取最长的那条
关键在第 3 步:正则一旦命中,就会覆盖掉普通前缀匹配的结果。
所以 location / { ... } 和 location ~* \.(js|css)$ { ... } 同时存在时,
后者优先——即使前者写得「更具体」。
单页应用的典型写法
root /var/www/app;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
# 静态资源单独一条,避免被上面的兜底吃掉
location /assets/ {
try_files $uri =404;
expires 7d;
add_header Cache-Control "public";
}
try_files $uri $uri/ /index.html 的含义是:
先按原路径找文件,再按目录找,都不存在就把请求内部重写到 /index.html,
由前端路由接管。这样刷新 /notes/abc 不会 404。
但这条兜底对 /assets/ 同样生效。如果某个 js 文件名写错,
浏览器拿到的是一份 200 的 HTML,控制台报
Unexpected token '<'——排查起来会绕很远。
所以静态目录要单独写一条,末尾用 =404,找不到就老实返回 404。
几个容易忽略的细节
末尾的斜杠不是装饰
location /assets/ 只匹配以 /assets/ 开头的路径;
location /assets 会同时匹配 /assets-foo 这种无关路径。
静态目录一律带尾斜杠。
root 和 alias 的拼接规则不同
| 指令 | 请求 /img/a.png 时实际查找 |
|---|---|
root /var/www; | /var/www/img/a.png |
alias /data/pic/; | /data/pic/a.png |
用 alias 时它会把 location 前缀整段替换掉,所以路径末尾要不要斜杠、
是否重复了一层目录,很容易配错。配完用
curl -I https://站点/img/a.png 实测一次最稳。
改完一定要先 nginx -t
语法错误时 reload 会失败但旧进程继续服务,容易误以为「改了没生效」。 流程固定成两步:
nginx -t && systemctl reload nginx
&& 保证了测试不通过就不 reload,线上不会因为一次手误整个站挂掉。
排查时看什么
遇到「页面不对」先分清是 Nginx 给错了文件,还是应用自己返回错了内容。
在日志里加 $request_filename 能直接看出最终落到磁盘的哪个路径:
log_format debug '$remote_addr "$request" -> $request_filename '
'status=$status';
access_log /var/log/nginx/debug.log debug;
临时开、查完就关。确认是路径拼接问题还是 try_files 兜底问题,通常一眼就能看出来。
← 返回笔记列表