单页应用刷新报404是因nginx未配置路由回退,需在location /块中按序配置root、index和try_files $uri $uri/ /index.html,并单独配置location /api/代理后端,同时设置html不缓存、静态资源哈希命名与长期缓存。

单页应用刷新报 404,不是前端代码错了,而是 Nginx 没理解你的路由意图。它老老实实去找 /user/profile 这个文件,可你压根没放这个文件——所有页面都藏在 index.html 里,靠 JS 动态渲染。try_files 就是告诉 Nginx:“先找真实文件,找不到?别急,交还给 index.html,让前端自己处理。”
核心配置:location / 里写对这行
必须放在 location / 块内,且 root 要在它前面:
-
root /usr/share/nginx/html;(路径要和你构建产物实际位置一致) -
index index.html;(显式声明默认首页) -
try_files $uri $uri/ /index.html;(顺序不能错:先查文件,再查目录,最后兜底)
这三行一起生效,$uri 匹配 /js/app.js 这类资源,$uri/ 处理 /assets/ 这样的目录请求,/index.html 则捕获所有其他路径,比如 /dashboard 或 /product/123。
避开 API 请求被误捕获
如果你的后端接口走 /api/,得单独声明,否则它也会被 try_files 拉去 index.html:
- 用
location /api/ { ... }(末尾带斜杠,强制前缀精确匹配) -
proxy_pass http://backend/;(结尾也加斜杠,保证路径透传不丢失) - 确保这个
location /api/块写在location /前面或同级,Nginx 会按最长前缀优先匹配
静态资源别被 HTML 缓存搞乱
启用 try_files 后,浏览器可能缓存了旧版 index.html,导致新路由加载空白或报错:
- 给 HTML 加强制不缓存:
add_header Cache-Control "no-cache, no-store, must-revalidate"; - JS/CSS/图片等资源用内容哈希命名(如
app.a1b2c3.js),并设置长期缓存:expires 1y; - 确认构建输出的
index.html真的在root指向的目录下
验证是否生效的小方法
改完别急着 reload,先快速检查两件事:
- 运行
nginx -t确保语法无误 - 用
curl -I http://localhost/some-random-path看响应头:状态码要是200,Content-Type是text/html,且没返回404
如果看到 200 并返回了 index.html 的内容,说明已接管成功。










