root在非根路径下404是因为它拼接完整uri导致路径多出子目录;应改用alias并配^~前缀、末尾斜杠,try_files回退路径和前端publicpath均须与子目录一致。

为什么 root 在非根路径下会 404
直接把 SPA 打包产物放到 /app/ 子目录,再用 root /var/www/dist; + location /app/ { ... },几乎必然触发 404。因为 root 拼接的是完整 URI 路径:请求 /app/js/app.js 时,Nginx 会去查 /var/www/dist/app/js/app.js —— 但实际文件在 /var/www/dist/js/app.js,中间多了一层 app/。
正确做法是用 alias 替代 root,它只替换匹配到的 location 前缀部分:
-
location ^~ /app/ { alias /var/www/dist/; }→ 请求/app/js/app.js映射到/var/www/dist/js/app.js - 必须加
^~前缀,否则正则 location 可能干扰匹配顺序 -
alias值末尾的/很关键:漏掉会导致路径错位(如写成alias /var/www/dist,就会少一层斜杠)
try_files 的回退路径必须带子目录前缀
SPA 的核心是前端路由接管所有非资源请求,所以 try_files 最后一项不能写成 /index.html —— 那会跳转到根路径,脱离当前子目录上下文,导致 JS/CSS 加载失败或路由错乱。
正确写法是让回退也落在同一子目录内:
- 错误:
try_files $uri $uri/ /index.html;(回退到根目录的index.html) - 正确:
try_files $uri $uri/ /app/index.html;(注意/app/前缀与 location 一致) - 如果用了
alias,index指令也要对齐:index index.html;即可,因为alias已经定位到 dist 目录
如何支持深层路由刷新不 404
用户直接访问 /app/user/profile 或按 F5 刷新时,Nginx 默认尝试找该路径对应的真实文件,找不到就报 404。必须把这类请求兜底到子目录下的 index.html,由前端路由处理。
完整 location 块示例:
location ^~ /app/ {
alias /var/www/dist/;
index index.html;
try_files $uri $uri/ /app/index.html;
}
-
^~确保该规则优先于可能存在的正则 location(比如~ \.js$) - 所有静态资源(
.js、.css、图片等)由前两项$uri和$uri/直接命中 - 任何未命中资源的请求(如
/app/xxx),最终 fallback 到/app/index.html,且该 HTML 文件能正常加载相对路径的 JS/CSS
前端构建时必须配 publicPath
Nginx 配置只是后半段;如果前端打包时没告诉它“我将来要跑在 /app/ 下”,生成的 index.html 里所有 script 和 link 标签仍会从根路径加载资源,比如 /js/app.js,而不是 /app/js/app.js。
以 Vue CLI 为例,必须在 vue.config.js 中设置:
module.exports = {
publicPath: '/app/'
}
- React(Create React App)需设
homepage字段为"./app"或"/app/"(build 后资源路径依赖此) - Vite 用户改
base: '/app/' - 漏掉这步,Nginx 配置再完美,页面也会白屏——控制台报一堆 404 加载 JS/CSS
最常被忽略的其实是前后端路径协同:Nginx 的 alias 和 try_files 回退路径必须与前端的 publicPath 完全一致,差一个字符都会导致资源加载断裂或路由失效。











