React+Node.js跨域POST请求失败问题求助
解决React前端与原生Node.js后端的CORS POST请求问题
问题场景
- React前端运行在
localhost:3000,原生Node.js后端运行在localhost:4000 - GET请求可正常获取数据,但POST请求无法向数据库写入数据
- POSTMAN测试POST请求正常,但前端控制台报CORS相关错误
前端代码
const sendData = async (event: any): Promise<void> => { console.log("hello"); event.preventDefault(); const response = await fetch(`${_DATA_URL_}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(employeeForm), }); const data = await response.json(); console.log(data); };
后端路由代码
const Router = (req, res) => { res.setHeader("Access-Control-Allow-Origin", "*"); res.setHeader( "Access-Control-Allow-Headers", "Content-Type, Accept, Origin, Authorization" ); res.setHeader( "Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS" ); console.log("hello"); //debug if (req.method === "GET") { if (req.url === "/api/employees") { getEmployees(req, res); } else if (req.url.match(/\/api\/employees\/(\w{4}-?){3}/)) { const requestID = req.url.split("/")[3]; getEmployee(req, res, requestID); } else { res.statusCode = 404; res.setHeader("Content-Type", "application/json"); res.end(JSON.stringify({ message: `Error : ${req.url} not found !` })); } } if (req.method === "POST") { if (req.url === "/api/employees") { createEmployee(req, res); } else { res.setHeader("Content-Type", "application/json"); res.end(JSON.stringify({ message: `Error : ${req.url} not found !` })); } } if (req.method === "DELETE") { if (req.url.match(/\/api\/employees\/(\w{4}-?){3}/)) { const requestID = req.url.split("/")[3]; deleteEmployee(req, res, requestID); } else { res.statusCode = 404; res.setHeader("Content-Type", "application/json"); res.end(JSON.stringify({ message: `Error : ${req.url} not found !` })); } } if (req.method === "PUT") { if (req.url.match(/\/api\/employees\/(\w{4}-?){3}/)) { const requestID = req.url.split("/")[3]; updateEmployee(req, res, requestID); } else { res.statusCode = 404; res.setHeader("Content-Type", "application/json"); res.end(JSON.stringify({ message: `Error : ${req.url} not found !` })); } } };
问题原因
浏览器对非简单请求(比如设置了Content-Type: application/json的POST请求)会先发一个OPTIONS预检请求,用来确认后端是否允许跨域请求。当前你的后端路由没有处理OPTIONS请求的逻辑,导致预检请求得不到正确响应,浏览器拦截了后续的POST请求,从而触发CORS错误。
而GET请求属于简单请求,浏览器不会发送预检OPTIONS,直接发送请求,后端设置的CORS头能正常生效,所以GET可以正常工作。Postman不会发送预检请求,所以POST测试正常。
解决方案
在后端路由最顶部添加OPTIONS请求的处理逻辑,直接返回200状态码即可,因为预检请求只需要验证CORS配置,不需要处理业务逻辑:
修改后的后端路由代码
const Router = (req, res) => { res.setHeader("Access-Control-Allow-Origin", "*"); res.setHeader( "Access-Control-Allow-Headers", "Content-Type, Accept, Origin, Authorization" ); res.setHeader( "Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS" ); // 处理OPTIONS预检请求 if (req.method === "OPTIONS") { res.writeHead(200); res.end(); return; // 终止后续逻辑 } console.log("hello"); //debug if (req.method === "GET") { if (req.url === "/api/employees") { getEmployees(req, res); } else if (req.url.match(/\/api\/employees\/(\w{4}-?){3}/)) { const requestID = req.url.split("/")[3]; getEmployee(req, res, requestID); } else { res.statusCode = 404; res.setHeader("Content-Type", "application/json"); res.end(JSON.stringify({ message: `Error : ${req.url} not found !` })); } } if (req.method === "POST") { if (req.url === "/api/employees") { createEmployee(req, res); } else { res.setHeader("Content-Type", "application/json"); res.end(JSON.stringify({ message: `Error : ${req.url} not found !` })); } } if (req.method === "DELETE") { if (req.url.match(/\/api\/employees\/(\w{4}-?){3}/)) { const requestID = req.url.split("/")[3]; deleteEmployee(req, res, requestID); } else { res.statusCode = 404; res.setHeader("Content-Type", "application/json"); res.end(JSON.stringify({ message: `Error : ${req.url} not found !` })); } } if (req.method === "PUT") { if (req.url.match(/\/api\/employees\/(\w{4}-?){3}/)) { const requestID = req.url.split("/")[3]; updateEmployee(req, res, requestID); } else { res.statusCode = 404; res.setHeader("Content-Type", "application/json"); res.end(JSON.stringify({ message: `Error : ${req.url} not found !` })); } } };
添加这段OPTIONS处理逻辑后,浏览器的预检请求会得到正常响应,后续的POST请求就能顺利发送到后端,完成数据写入操作。
内容的提问来源于stack exchange,提问作者Nathan
相关产品推荐
相关产品推荐

