前端调后端接口 404 或超时,你想起来要配开发服务器代理。改完配置文件,保存,等热更新——然后发现还是 404。
现象
前端请求后端接口报 404 或者超时。打开项目配置,代理其实已经配好了,格式看起来也对,但请求还是打不到后端。
于是你开始反复检查配置、重启后端、换端口——都没用。有些人会怀疑是配置写错了,于是改来改去,越改越乱,最后即使配置本身是对的也被改坏了。
一个典型的旁证:改配置之前请求也是 404,改完还是 404,错误一模一样、连报错的路径都相同。这种"毫无变化"恰恰说明配置压根没被加载,否则至少错误形式会变。
根因
这个 IDE 的内置开发服务器在构建时读取代理配置——配置只在开发服务器启动的那一刻被加载一次,之后一直用内存里的那份。
你改了配置文件,热更新(HMR)只会重新加载代码模块,不会重新执行开发服务器的初始化流程,所以代理配置还是旧的。
这解释了一个很典型的困惑:"为什么我改了配置却像没改?"因为热更新的边界是"应用代码",不是"服务器启动参数"。
说到底,开发服务器有两类状态:一类是"跟着代码走"的(组件、样式、业务逻辑),改动会被 HMR 增量替换;另一类是"跟着进程走"的(监听端口、代理规则、别名、环境变量),只在进程启动时确定。后一类没有"热替换"的机制,只能整体重启。
解决
第一步,停止运行,然后重新运行。 必须是完整的"停 - 起":
- 不是保存文件;
- 不是刷新浏览器;
- 不是手动触发一次热更新。
开发服务器重新初始化时才会读取新的代理配置。很多人卡在这里的原因就是以为"保存了就等于生效了"。
第二步,验证是否生效。 看开发服务器启动时的控制台输出,通常会有代理规则的打印;或者直接发一个请求,看它有没有被转发到后端地址。如果后端日志里出现了这条请求,就说明代理生效了。
第三步,如果还是不行,检查配置本身的正确性。 常见错误:
// 以 vite 风格为例
server: {
proxy: {
'/api': {
target: 'http://127.0.0.1:8080',
changeOrigin: true,
// 路径重写规则,最容易配错的地方
rewrite: (p) => p.replace(/^\/api/, ''),
},
},
}
changeOrigin 和 rewrite 规则是最容易配错的两处——前者影响 Host 头,后者决定路径怎么映射到后端。配错时的表现就是"404 但后端日志里什么都没有",或者"请求打到了后端但路由不对"。前者通常是代理没匹配上,后者多半是 rewrite 把路径改错了:先用注释把 rewrite 关掉、看原始路径能不能对上后端路由,再决定要不要加。
同类现象还有一个:MIME 报错。 改了构建相关配置后页面报 MIME 类型错误,本质同样是"启动时读一次的配置没重新加载",也是靠完整重启解决。
延伸与预防
记住一条分界线:热更新覆盖代码,不覆盖"启动时读一次"的配置。
凡是属于以下类别的改动,都要完整重启:
- 代理配置;
- 构建配置(打包路径、别名、publicPath);
- 环境变量文件(
.env); - 服务器端口、HTTPS 证书;
- 依赖安装(
npm install之后常需要重启才能识别新包)。
把这条写进项目 README 的"常见问题",能省掉团队里每个人重复踩一次的时间。更根本的做法是:遇到"改了不生效",先问自己"这个改动是在代码里,还是在启动参数里"——这个分类能立刻告诉你该不该重启。
顺带一个实用技巧:如果怀疑是"配置没加载",可以在开发服务器启动时打印一次最终的配置对象(比如在配置文件里 console.log(server.proxy))。这样每次启动都能确认代理规则是不是按预期加载了,比改完再去浏览器里试快得多。