快速修复
# 一键:nginx 核心修复——不存在的路径回退到 SPA 入口,静态资源 404 单独暴露
# location /app/ { alias /path/to/dist/; try_files $uri $uri/ /app/index.html; }
# location /app/assets/ { alias /path/to/dist/assets/; try_files $uri =404; }
把这两段 location 按你的部署目录改好,nginx -t && nginx -s reload。
你会遇到什么
本地 vite dev 一切正常;打包部署到服务器后,访问首页正常、站内路由跳转也正常,但手动刷新子路由页面(深链)时白屏,控制台里深链请求返回 404。本地永远复现不了,问题只在部署后暴露。
本文路径:快速修复(30 秒一段命令)→ 一步步排查(可跳读)→ 原理与变体(症状/原因/证据)。赶时间直接跳到「快速修复」。
为什么会这样
vue-router 用 createWebHistory(HTML5 History 模式)时,URL 不带 #。刷新时浏览器直接向服务器请求子路由路径(如 /app/docs/setup),服务器上没有这个物理文件,于是返回 404 → 白屏。vite dev 自带 history fallback,所以本地永远正常。
| 场景 | 表现 |
|---|---|
| 站内跳转 | ✅ 前端路由接管,不发服务器请求 |
| 刷新深链 | ❌ 浏览器直接请求 /app/docs/setup,服务器无此文件 → 404 |
| 首页直接访问 | ✅ 物理文件存在 |
HTML5 History 模式(createWebHistory)把路由状态放进 URL 路径,刷新时浏览器不经过前端路由,直接向服务器发完整路径的请求——服务器按物理文件找 /app/docs/setup,找不到就 404。站内跳转不触发服务器请求(前端 router 拦截),所以「站内导航正常、一刷新就白屏」是这类问题的标志性特征。
vite dev 内置 history fallback(所有路径回退到 index.html),本地永远正常,部署后消失——这是「开发环境与生产环境静态服务器行为不同」的典型。
确定性推论:生产服务器必须配「未知路径回退到 index.html」:nginx try_files $uri $uri/ /index.html;、静态托管平台开 SPA fallback、或 Node 服务器 app.get('*', ...) 返回 index.html;配好后刷新深链返回 200 而不是 404 即修复。
一步步来
1. 排查第一步:base 一致性 — 排查
vite.config 的 base、createWebHistory(base)、服务器部署目录三者必须完全一致(尤其结尾 /)。部分资源 404 / 图标丢失通常是 base 不一致。
2. nginx history fallback(核心修复) — 必做
location /app/ {
alias /path/to/dist/;
try_files $uri $uri/ /app/index.html;
}
3. 静态资源 404 不能被 fallback 吞掉 — 必做
无差别 fallback 会把缺失的 JS/CSS 也返回 200 + HTML(动态 import 失败时更难排查,与 ChunkLoadError 互相印证)。给 assets 单独一个 location:
location /app/assets/ {
alias /path/to/dist/assets/;
try_files $uri =404;
}
4. Apache 等价写法 — 必做
.htaccess:RewriteEngine On + 文件/目录不存在时 rewrite 到 /app/index.html(逻辑同第 2 步)。
怎么确认修好了
curl 断言三类路径(预期输出):
curl -I http://你的域名/app/docs/setup
→ HTTP 200(深链回退到 HTML 入口)
curl -I http://你的域名/app/assets/main.js
→ HTTP 200(真实资源)
curl -I http://你的域名/app/assets/missing.js
→ HTTP 404(缺失资源正确暴露,不被吞)
浏览器刷新任意深链不再白屏(实测:修正后深链 200、真实资源 200、缺失资源 404)。
其它环境的表现
| 环境 | 说明 |
|---|---|
| nginx alias 部署 | 深链回退 + assets 独立 location(实测修正方案) |
| nginx root 部署 | 同样 try_files $uri $uri/ /index.html,注意 base 路径 |
| Apache | .htaccess rewrite,逻辑相同 |
| base 不一致 | 部分资源 404 / 图标丢失,先查 base 再查 fallback |
| 无差别 fallback | 缺失 JS 也返回 200 HTML,排查更难(实测踩坑) |
症状
本地 vite dev 一切正常;打包部署到服务器后,直接访问首页正常、站内路由跳转正常,但手动刷新子路由页面(深链)时白屏,控制台里深链请求返回 404。
原因
vue-router 使用 createWebHistory(HTML5 History 模式)时,URL 不带 #。刷新时浏览器直接向服务器请求子路由路径(如 /app/docs/setup),服务器上没有这个物理文件,于是返回 404 → 白屏。vite dev 自带 history fallback,所以本地永远复现不了,问题只在部署后暴露。
解法
- base 一致性(排查第一步):
vite.config的base、createWebHistory(base)、服务器部署目录三者必须完全一致(尤其结尾/)。部分资源 404 / 图标丢失通常是 base 不一致。 - nginx history fallback(核心修复):把不存在的路径回退到 SPA 入口:
location /app/ {
alias /path/to/dist/;
try_files $uri $uri/ /app/index.html;
}
- 静态资源 404 不能被 fallback 吞掉(实测修正):无差别 fallback 会把缺失的 JS/CSS 也返回 200 + HTML,动态 import 失败时更难排查(与 ChunkLoadError 条目互相印证)。给 assets 单独一个 location,让真实 404 暴露:
location /app/assets/ {
alias /path/to/dist/assets/;
try_files $uri =404;
}
- Apache 等价写法:
RewriteEngine On+ 文件/目录不存在时 rewrite 到/app/index.html(.htaccess,逻辑同 2)。
验证证据
- 本地实测(2026-08-29):nginx 1.28.3 + 最小 SPA fixture(
index.html+assets/),alias部署 +curl断言。 - 复现:无 fallback 时
GET /app/docs/setup→ 404(刷新白屏根因成立),/app/index.html→ 200。 - 文章解法:
try_files ... /app/index.html后深链 → 200(HTML 入口);但GET /app/assets/missing.js→ 200 HTML —— 静态 404 被吞(文章未提的坑)。 - 修正后:深链 200、真实资源 200、缺失资源 404(正确暴露)。
实测复现日志(2026-08-29)
适用工具 (2)
本问题方案已挂到下列工具的方案页——从工具页也能回到这里,双向可达。
vite-deploynginx · 外部工具成套方案 (组合包)
这个问题包含在下列成套安装方案中。
- 网页部署验证 verified
来源与证据
← 构建与部署 问题域 | 问题货架 | 遇到其它问题?去 问题空间 提交求助卡