Nginx部署SPA时刷新子路由返回404,根本原因是其默认按真实文件路径查找,而SPA所有路由均由index.html动态渲染;解决方法是在location /中配置try_files $uri $uri/ /index.html,并配合root和index指令,确保静态资源直通、API路由优先匹配、子路径正确调整fallback路径。

Nginx 部署 Vue、React 等单页应用(SPA)时,用户直接访问或刷新 /user/profile 这类前端路由,会返回 404。这不是前端代码问题,而是 Nginx 默认按真实文件路径查找资源,而 SPA 所有页面都由 index.html + JS 动态渲染。try_files 就是用来告诉 Nginx:“找不到就别报错,交还给 index.html”。
核心配置只有一行,但必须放对位置、配好前提
location / {
root /var/www/my-spa;
index index.html;
try_files $uri $uri/ /index.html;
}这三行要一起出现,缺一不可。
为什么这行指令能解决问题
-
$uri:检查请求路径是否对应真实文件,比如/logo.png或/js/app.js,存在就直接返回 -
$uri/:检查是否为真实目录,比如/assets/,存在则尝试加载其下的index.html(需配合index index.html;) -
/index.html:前面两项都不匹配时,内部重写请求到根目录的index.html,浏览器地址栏不变,但内容是入口文件,由前端路由接管渲染
注意:顺序不能调换。如果把 /index.html 放在前面,所有请求都会被兜底,静态资源就加载不了。
避免 API 请求被误兜底
前后端同域(如接口走 /api/login)时,必须单独声明 API 路由,否则它也会被 try_files 拦下来返回 HTML:
location /api/ {
proxy_pass http://127.0.0.1:3000/;
proxy_set_header Host $host;
}
location / {
root /var/www/my-spa;
index index.html;
try_files $uri $uri/ /index.html;
}Nginx 匹配遵循“最长前缀优先”,所以 /api/ 一定先于 / 生效,不会进 try_files 流程。
静态资源要直通,不能被兜底
JS、CSS、图片等必须直接返回,不能落到 /index.html。加一条正则 location 提前拦截:
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?|ttf|eot|webp)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}这条规则优先级高于 location /,命中后直接返回文件,不进入 try_files 判断。
部署在子路径(如 /admin/)怎么配
若访问地址是 https://example.com/admin/,不能继续用 /index.html:
-
推荐用
alias(更清晰):location /admin/ { alias /var/www/my-spa/; try_files $uri $uri/ /admin/index.html; }注意:
alias后路径末尾要有/;/admin/index.html是相对于alias目录的内部路径。 -
若用
root,物理路径需包含子目录结构:location /admin/ { root /var/www; try_files $uri $uri/ /admin/index.html; }此时 Nginx 会拼出
/var/www/admin/index.html,你要确保该文件真实存在。
验证是否生效的简单方法
- 运行
nginx -t确认语法正确,再systemctl reload nginx - 用
curl -I http://localhost/some-unknown-path:状态码应为200,Content-Type是text/html - 浏览器打开开发者工具 → Network 标签,刷新
/dashboard,看 HTML 响应是否是index.html源码,同时 JS/CSS 请求状态码都应为200
不复杂但容易忽略。


















