一刷新就404是因为服务器未将非根路径请求兜底至index.html;uni-app H5是SPA,路由由前端JS控制,但刷新时请求直达Nginx/Apache,而服务器只返回真实存在的文件,/user/profile等虚拟路径不存在即返回404。
为什么一刷新就 404?不是代码错,是服务器没交棒
根本原因很直接:uni-app h5 是单页应用(spa),所有路由由前端 js 控制;但浏览器刷新时,请求直接打到 nginx/apache,而服务器只认真实存在的文件路径(比如 /user/profile 下根本没有 html 文件),于是返回 404 —— 根本没机会加载 index.html 和 vue router。
这不是 uni-app 的 bug,也不是你 pages.json 写错了,而是 SPA 路由和传统静态服务器的天然冲突。
- 本地
npm run serve不报错?因为 webpack-dev-server 默认开了historyApiFallback,自动兜底,这不能代表线上环境 - 点击跳转正常、刷新就挂?100% 是服务器没把非根路径请求回退给
index.html - 部署在子目录(如
/h5/或/admin/)却没改配置?JS/CSS 加载失败 + 刷新 404 会一起出现
Nginx 配置 try_files 是硬性前提,不是可选项
如果你能改服务器,try_files 是 history 模式唯一靠谱的解法。光靠前端改 mode 或加 base 没用,服务器不配合照样 404。
最简有效写法(根目录部署):
location / {
try_files $uri $uri/ /index.html;
}
但注意这些细节:
- 必须放在
server块里,且要覆盖你实际部署的路径范围 - 如果部署在子目录(如
https://a.com/myapp/),要严格匹配前缀:location ^~ /myapp/ { alias /var/www/myapp/; try_files $uri $uri/ /myapp/index.html; } -
alias和root别混:用alias时,末尾斜杠和路径拼接逻辑完全不同,写错会导致静态资源 404 - 改完必须执行
nginx -t && nginx -s reload,仅重启服务或刷新页面无效
manifest.json 里 mode 和 base 必须对齐 publicPath
history 模式下,mode、base、publicPath 三者不一致,等于白配。哪怕 Nginx 配对了,JS 也加载不了,首页都进不去。
例如部署在 https://example.com/app/:
-
vue.config.js中:publicPath: process.env.NODE_ENV === 'production' ? '/app/' : '/' -
pages.json中:"h5": { "router": { "base": "/app/" } } -
manifest.json中:"h5": { "router": { "mode": "history" } }
三个值必须完全一致,包括末尾斜杠 —— /app 和 /app/ 是不同路径,会导致资源 404。
hash 模式则宽松得多:publicPath 通常保持 './' 即可,base 可不填,mode 设为 "hash" 后 URL 变成 https://a.com/#/pages/user,服务器全程不参与路由解析。
本地验证别信 HBuilderX,要用静态服务器模拟真实环境
HBuilderX 的「运行到浏览器」走的是开发服务器,自带 fallback,刷一百次都正常 —— 这反而掩盖问题。
上线前务必用真实静态服务验证:
- 构建后进入
dist/build/h5目录 - 运行:
npx http-server -p 8080 -c-1(-c-1禁用缓存) - 手动访问
http://localhost:8080/pages/user/profile并刷新,看是否 404
这个环节卡住,说明前端配置或构建路径仍有问题;如果通过,再上 Nginx 就只差服务器那行 try_files 了。
最容易被忽略的是:CDN 或对象存储(如又拍云、腾讯云 COS)也需要开启「单页应用支持」或手动配置重写规则,否则即使 Nginx 对了,用户实际访问的仍是 CDN 返回的 404。


















