
本文详解本地开发时 fetch('/saves') 返回 404 的根本原因——请求未指定后端服务端口,导致浏览器默认向当前页面所在端口(如 Live Server 的 :5500)发起同源请求,而非目标 Express 服务端口(如 :5500 冲突或实际为 :3000/:5000 等),并提供完整排查路径、代码修正与最佳实践。
本文详解本地开发时 fetch('/saves') 返回 404 的根本原因——请求未指定后端服务端口,导致浏览器默认向当前页面所在端口(如 live server 的 :5500)发起同源请求,而非目标 express 服务端口(如 :3000/:5000 等),并提供完整排查路径、代码修正与最佳实践。
在本地全栈开发中,前端与后端常运行于不同端口(例如前端通过 VS Code Live Server 启动在 http://127.0.0.1:5500,而后端 Express 服务监听 http://localhost:3000 或 http://127.0.0.1:5000)。此时若前端使用相对路径 fetch('/saves'),浏览器会自动将请求发往当前页面的协议 + 域名 + 端口,即 http://127.0.0.1:5500/saves —— 而该地址并不存在 Express 服务,因此返回标准 Express “Cannot GET /saves” HTML 错误页(HTTP 404),这正是你看到的
Cannot GET /saves 响应。⚠️ 关键误区:fetch('/saves') 并非指向“你的后端”,而是严格遵循同源策略(Same-Origin Policy),只向当前页面来源(Origin)发送请求。你的 Postman 能成功,是因为它直接访问 http://localhost:5500/saves(你后端实际监听的地址),而浏览器中的 JS 不会自动跨端口代理。
✅ 正确做法:显式指定后端完整 URL(含端口)
假设你的 Express 服务实际运行在 http://localhost:5000(这是更常见的配置,而非 :5500——注意:Live Server 占用 :5500,Express 若也设为 :5500 将端口冲突!请检查 server.js 中 port = 5500 是否与前端冲突):
前端设计与 UI/UX 全方位优化专家。覆盖视觉层次、排版系统、色彩理论、响应式布局、交互体验、动画动效、无障碍访问、性能优化八大维度,帮助开发者将普通页面升级为高品质产品级界面。前端设计与 UI/UX 全方位优化专家。覆盖视觉层次、排版系统、色彩理论、响应式布局、交互体验、动画动效、无障碍访问、性能优化八大维度,帮助开发者将普通页面升级为高品质产品级界面。
// ✅ 客户端正确调用方式(推荐:使用环境变量或配置管理)
function getSaveObject() {
// 显式指定后端地址(确保端口匹配真实服务)
const url = 'http://localhost:5000/saves'; // ← 关键:必须带端口!
fetch(url)
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json(); // 直接解析 JSON,无需 .text()
})
.then(data => {
console.log('Fetched saves:', data);
return data;
})
.catch(error => {
console.error('Fetch failed:', error);
// 可在此统一处理网络错误、404、500 等
});
}
? 排查与验证步骤:
- 确认后端真实监听端口:检查 server.js 中 const port = 5500 —— 若前端 Live Server 已占 :5500,则 Express 必须改用其他端口(如 3000、5000、8080),否则启动失败或被抢占;
- 验证后端是否可达:在浏览器中直接访问 http://localhost:5000/saves(替换为你的实际端口),应返回 JSON 数据(如你 Postman 所见);
- 检查 CORS 配置:你当前的 cors({ origin: [...] }) 是正确的,但需确保 allowedOrigins 包含前端实际地址(如 http://127.0.0.1:5500 和 http://localhost:5500),且 app.use(cors(...)) 必须在所有路由注册之后(你代码中 .use(dbRouter) 后才挂载 cors,顺序有误!);
- 修正中间件顺序(重要):CORS 应在路由前启用,否则路由可能提前响应而跳过 CORS 头:
// ✅ server.js 中间件顺序修正(关键!)
app.use(express.json());
app.use(cors({ /* ... */ })); // ← 放在路由之前
app.use(serverRouter);
app.use(dbRouter); // ← 路由应在 CORS 之后
? 进阶建议(提升健壮性):
- 使用代理避免跨域(开发阶段):在前端项目根目录创建 setupProxy.js(React)或配置 Vite/Webpack Dev Server 代理,将 /api 请求转发至 http://localhost:5000,前端即可安全使用 fetch('/api/saves');
- 环境变量区分环境:在客户端通过 import.meta.env.VITE_API_BASE_URL(Vite)或 process.env.REACT_APP_API_URL(React)注入后端地址,避免硬编码;
- 服务端日志辅助诊断:在 dbRouter.js 的 /saves GET 路由开头添加 console.log('GET /saves received'),若无输出,说明请求根本未到达后端,进一步印证是前端 URL 错误。
? 总结:404 的根源不是后端路由未定义,而是前端请求发错了地方。牢记——fetch('/xxx') 永远发给当前页面的 Origin;要调用独立后端,必须写全 http://host:port/xxx。修正端口、调整中间件顺序、验证可达性,三步即可解决。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










