最近一个后台项目从老架构迁到 Vite,本地开发一直没问题,接口请求、路由跳转、资源加载都正常。
结果打包丢到测试环境之后,页面能打开,但部分接口直接 404。
一开始以为是后端没部署,后来发现不是。后端接口都在,Postman 也能正常调通,只有前端打包后的请求路径不对。
最后定位下来,问题出在Vite 的base配置、Nginx 路由、以及接口代理环境差异这几个点没对齐。
下面把排查过程记一下,避免后面再踩同样的坑。
问题现象
本地开发环境:
pnpm dev页面正常,接口请求路径也没问题,比如:
/api/user/info /api/order/list打包之后部署到测试环境,访问地址变成了:
https://test.example.com/admin/这时候页面能打开,但接口请求变成了:
https://test.example.com/api/user/info后端实际接口路径是:
https://test.example.com/admin-api/user/info所以前端请求直接 404。
第一反应:先看网络面板
打开浏览器 Network 面板,先看失败请求。
几个关键信息:
- 请求状态:
404 - 请求地址:
/api/user/info - 页面地址:
/admin/ - 后端真实接口前缀:
/admin-api/
到这里基本可以确认,不是后端挂了,而是前端打包后的请求路径和后端实际路径没对上。
第二步:看 Vite 配置
项目里原来有个.env.production:
VITE_API_BASE_URL=/api接口封装里大概是这么用的:
const request = axios.create({ baseURL: import.meta.env.VITE_API_BASE_URL, timeout: 10000 })本地开发没问题,是因为 Vite dev server 里配了代理:
server: { proxy: { '/api': { target: 'http://127.0.0.1:8080', changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, '') } } }也就是说,本地请求/api/user/info,会被代理到:
http://127.0.0.1:8080/user/info所以本地看起来没问题。
但打包之后,前端静态资源是直接由 Nginx 托管的,Vite 的 proxy 不会生效。
这时候/api/user/info就会直接打到 Nginx,而 Nginx 没有对应的转发规则,自然 404。
第三步:发现 base 也有问题
排查完接口前缀后,又发现另一个问题。
测试环境访问地址是:
https://test.example.com/admin/但打包后部分静态资源请求路径是:
/assets/index-xxx.js而不是:
/admin/assets/index-xxx.js这就会导致资源加载失败,页面白屏或者部分组件加载不出来。
原因是vite.config.js里没有配置base,默认是/。
改成:
export default defineConfig({ base: '/admin/', plugins: [vue()], server: { proxy: { '/api': { target: 'http://127.0.0.1:8080', changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, '') } } } })改完之后,静态资源路径就对了。
第四步:Nginx 配置没跟上
前端配置改完后,接口还是 404。
因为生产环境没有 Vite proxy,所以 Nginx 需要把/api转发到后端服务。
原来的 Nginx 配置大概是这样:
location / { root /data/web/admin; index index.html; try_files $uri $uri/ /index.html; }这个配置只能处理前端路由和静态资源,不能处理接口转发。
后面补了一段:
location /api/ { proxy_pass http://127.0.0.1:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }这里要注意一个细节:
proxy_pass http://127.0.0.1:8080/;末尾这个/很关键。
如果写成:
proxy_pass http://127.0.0.1:8080;那请求/api/user/info转发到后端后,路径会变成:
/api/user/info如果后端接口实际是:
/user/info那还是会 404。
加上末尾/之后,/api/会被替换掉,转发路径变成:
/user/info这个点很容易忽略。
最终改动
最后主要改了三个地方。
1.vite.config.js
export default defineConfig({ base: '/admin/', plugins: [vue()], server: { proxy: { '/api': { target: 'http://127.0.0.1:8080', changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, '') } } } })2..env.production
VITE_API_BASE_URL=/api3. Nginx 配置
server { listen 80; server_name test.example.com; location /admin { alias /data/web/admin; index index.html; try_files $uri $uri/ /admin/index.html; } location /api/ { proxy_pass http://127.0.0.1:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }改完之后,重新打包部署,接口和资源都正常了。
问题原因总结
这次问题本质上是三个环境差异没对齐:
| 环境 | 接口代理 | 静态资源路径 |
|---|---|---|
| 本地 dev | Vite proxy 生效 | /没问题 |
| 测试环境 | Nginx 转发 | 需要/admin/ |
| 后端接口 | 真实路径不同 | 需要路径重写 |
本地开发时,Vite proxy 把很多路径问题掩盖了。打包上线后,proxy 没了,所有路径都得靠 Nginx 和前端配置自己处理,所以问题就暴露出来了。
几个容易踩的点
1. Vite proxy 只在开发环境生效
这个很关键。
很多人本地调试接口没问题,就觉得配置没问题,结果一打包就挂。
生产环境一定要单独处理接口转发,不能依赖 Vite proxy。
2.base配置要和部署路径一致
如果项目不是部署在根目录,而是类似:
https://test.example.com/admin/那base一定要配置成:
base: '/admin/'不然静态资源路径会错。
3. Nginxproxy_pass末尾斜杠别乱删
proxy_pass http://127.0.0.1:8080/;这个/会影响路径拼接。
如果前端请求:
/api/user/infoNginx 配置:
location /api/ { proxy_pass http://127.0.0.1:8080/; }转发后是:
/user/info如果去掉末尾/:
proxy_pass http://127.0.0.1:8080;转发后是:
/api/user/info这个差别很细,但排查起来很烦。
4. 前端环境变量不要写死本地地址
之前项目里有人直接在.env.production里写过:
VITE_API_BASE_URL=http://127.0.0.1:8080这种配置本地看着能通,打包后直接炸。
生产环境尽量用相对路径:
VITE_API_BASE_URL=/api然后通过 Nginx 转发。
5. 排查时先看 Network,不要一上来猜后端问题
这次一开始差点让后端同事查半天日志。
后来 Network 面板一看,请求地址就不对,问题基本就锁定在前端部署配置上了。
前端 404 不一定都是前端代码问题,也可能是 Nginx、base 路径、代理配置问题。
排查顺序
后面再遇到类似问题,可以按这个顺序看:
- 打开浏览器 Network 面板,看失败请求的真实地址
- 确认本地请求地址和线上请求地址是否一致
- 检查
vite.config.js里的base配置 - 检查
.env.production里的接口前缀 - 确认 Nginx 是否配置了接口转发
- 检查
proxy_pass末尾有没有/ - 确认前端部署目录和访问路径是否一致
最后
这个问题不算复杂,但挺典型。
Vite 项目本地跑通只是第一步,真正麻烦的是上线后各种路径、代理、环境变量对齐。
尤其是从老项目迁移过来的时候,原来可能用 Vue CLI、Webpack、Nginx 反向代理,换到 Vite 之后,配置方式变了,但思路其实差不多。
关键还是搞清楚:
- 本地请求是怎么走的
- 打包后请求是怎么走的
- Nginx 到底转发了什么路径
把这三条链路理清楚,大部分 404 问题都能快速定位。