localhost环境下Chrome出现CORS错误,Postman可正常请求的问题排查
我是开发新手,正在做联系表单。用Postman请求http://localhost:5000/Kontakt接口完全正常,但前端(运行在http://localhost:5173)用fetch请求时触发CORS错误。我已经在后端设置了允许指定源的请求头,但Chrome提示请求资源不存在Access-Control-Allow-Origin头,设置为*也没用。希望得到无需代理的代码解决方案。
前端代码
async function submitHandler() { try { const res = await fetch("http://localhost:5000/Kontakt", { method: "POST", mode: "cors", headers: { "content-type": "application/json" }, body: JSON.stringify(formik.values) }); console.log(res.message); if (res.message == "message saved") { formik.resetForm(); navigate("/Bestaetigung"); } else { navigate("/Fehlgeschlagen"); console.log("fehlgeschlagen1") } } catch (error) { navigate("/Fehlgeschlagen"); console.error(error); } };
后端代码
主文件
const express = require("express"); const login_routes = require('./router/registered.js').registered; const general_routes = require('./router/general.js').general; const app = express(); app.use(express.json()); const PORT = 5000; app.use("/", general_routes); app.listen(PORT,()=>console.log("Server is running"));
路由文件(/Kontakt接口)
general_users.post("/Kontakt", (req, res) => { var content = req.body; content = JSON.stringify(content) res.setHeader("Access-Control-Allow-Origin", "http://localhost:5173"); res.setHeader("Access-Control-Request-Method", "*"); res.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT"); res.setHeader("Access-Control-Allow-Headers", "Content-Type"); fs.appendFile("messages.txt", content, err => { if (err) { console.error(err); return res.status(500).json({error: "message not saved"}); } else { res.status(200).json({message: "message saved"}); } }); });
Chrome报错信息
Access to fetch at 'http://localhost:5000/Kontakt' from origin 'http://localhost:5173' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
问题原因
浏览器发送包含Content-Type: application/json的POST请求时,会先发送OPTIONS预请求,用来确认服务器是否允许跨域请求。你的后端只处理了POST请求,没有处理OPTIONS请求,导致预请求的响应没有携带CORS头,从而触发报错。
解决方案
方案1:手动处理OPTIONS请求
在后端添加对OPTIONS请求的处理,确保预请求能拿到正确的CORS头。
全局处理所有OPTIONS请求(修改后端主文件)
在app.use("/", general_routes);之前添加:
const express = require("express"); const login_routes = require('./router/registered.js').registered; const general_routes = require('./router/general.js').general; const app = express(); app.use(express.json()); // 处理所有OPTIONS预请求 app.options('*', (req, res) => { res.setHeader("Access-Control-Allow-Origin", "http://localhost:5173"); res.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT"); res.setHeader("Access-Control-Allow-Headers", "Content-Type"); res.sendStatus(200); }); const PORT = 5000; app.use("/", general_routes); app.listen(PORT,()=>console.log("Server is running"));
仅针对/Kontakt接口处理(修改路由文件)
在POST路由上方添加OPTIONS路由:
// 处理OPTIONS预请求 general_users.options("/Kontakt", (req, res) => { res.setHeader("Access-Control-Allow-Origin", "http://localhost:5173"); res.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT"); res.setHeader("Access-Control-Allow-Headers", "Content-Type"); res.sendStatus(200); }); // 原POST路由 general_users.post("/Kontakt", (req, res) => { var content = req.body; content = JSON.stringify(content) res.setHeader("Access-Control-Allow-Origin", "http://localhost:5173"); res.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT"); res.setHeader("Access-Control-Allow-Headers", "Content-Type"); fs.appendFile("messages.txt", content, err => { if (err) { console.error(err); return res.status(500).json({error: "message not saved"}); } else { res.status(200).json({message: "message saved"}); } }); });
方案2:使用express-cors中间件(推荐)
用官方维护的cors中间件可以更简洁地处理CORS,避免手动配置出错。
- 安装cors:
npm install cors
- 修改后端主文件:
const express = require("express"); const cors = require("cors"); const login_routes = require('./router/registered.js').registered; const general_routes = require('./router/general.js').general; const app = express(); // 配置cors,允许指定源 app.use(cors({ origin: "http://localhost:5173", methods: ["POST", "GET", "PUT"], allowedHeaders: ["Content-Type"] })); app.use(express.json()); const PORT = 5000; app.use("/", general_routes); app.listen(PORT,()=>console.log("Server is running"));
- 此时可以删除路由文件里手动设置的CORS头,中间件会自动处理。
前端代码修复
你直接访问res.message是错误的,fetch返回的res是Response对象,需要先解析成JSON才能拿到响应数据:
async function submitHandler() { try { const res = await fetch("http://localhost:5000/Kontakt", { method: "POST", mode: "cors", headers: { "content-type": "application/json" }, body: JSON.stringify(formik.values) }); // 先解析响应为JSON const data = await res.json(); console.log(data.message); if (data.message == "message saved") { formik.resetForm(); navigate("/Bestaetigung"); } else { navigate("/Fehlgeschlagen"); console.log("fehlgeschlagen1") } } catch (error) { navigate("/Fehlgeschlagen"); console.error(error); } };
内容的提问来源于stack exchange,提问作者mahas

