纯HTML页面script标签中fetch请求本地接口失败原因咨询
问题根因
这个报错和框架无关,核心是浏览器同源策略触发的CORS(跨域资源共享)拦截:
- 浏览器默认禁止脚本向和当前页面不同源(协议、域名、端口三者任意一个不一致)的接口发起请求,防止恶意站点窃取数据,拦截发生在浏览器侧,请求要么根本没发出去,要么响应被浏览器拦截,前端就会拿到
TypeError: Failed to fetch的通用错误。 - 你之前React项目请求正常,是因为React本地开发服务(通常跑在3000端口)配置了代理规则:
/api开头的请求会被开发服务自动转发到后端端口,浏览器视角下请求始终发往当前页面所在的3000端口,属于同源请求,自然不会被拦截。如果去掉代理直接跨端口请求后端,React项目一样会报相同错误。 - 你直接双击打开本地HTML文件时,页面的源是
file://协议,和后端接口的http://localhost:5000源完全不匹配,直接触发跨域拦截。 - 当你通过Express的5000端口返回HTML页面时,页面访问地址是
http://localhost:5000,和接口地址http://localhost:5000/api/*完全同源,没有跨域限制,所以请求能正常工作。
另外你的现有后端代码还存在一个隐藏bug:没有配置JSON请求体解析中间件,就算跨域问题解决,POST接口里的req.body会是undefined,拿不到前端传的参数。
修复方案
根据你的开发场景选对应方案即可:
方案1:前后端同源部署(你当前已经在用的方式)
把前端静态文件都交给Express服务托管,所有页面和接口都走同一个5000端口,天然不存在跨域问题,适合小型项目部署。注意要补上缺失的中间件配置,在所有路由注册前加两行代码:
// 解析JSON格式请求体 app.use(express.json()); // 如果你有静态资源(css、js、图片等),加这行托管public文件夹 app.use(express.static(path.join(__dirname, "public")));
方案2:前后端分离部署/本地单独打开HTML调试
给Express配置CORS中间件,允许指定源的跨域请求:
- 安装cors依赖:
npm install cors - 在Express入口文件中,所有路由注册前添加配置:
const cors = require("cors"); const app = express(); // 开发环境可直接放开所有跨域请求 app.use(cors()); // 生产环境建议只配置允许的前端源,比如: // app.use(cors({ origin: "http://你的前端页面地址" })) // 别忘了加JSON解析中间件 app.use(express.json()); // 后面再写app.use("/api", testRoute)这类路由注册逻辑
注意:部分浏览器会直接拦截
file://协议源的跨域请求,即使配了CORS也无法正常请求,本地调试建议用静态文件服务(比如VSCode的Live Server插件)打开HTML,再把Live Server的地址加入CORS允许列表即可。
内容的提问来源于stack exchange,提问作者Ayush Srivastava
相关产品推荐
相关产品推荐

