NodeJS+Express接收React POST请求req.body为空问题排查
问题根因
Access-Control-Allow-*系列是服务端返回给浏览器的CORS响应头,绝对不能在前端请求头里手动添加,手动加这类头反而会触发异常CORS校验逻辑。- 带
Content-Type: application/json的POST请求属于CORS非简单请求,浏览器会自动先发OPTIONS方法的预检请求,之前的配置要么没有正确响应预检,要么中间件顺序错误导致预检被拦截,才会触发跨域报错。 - 前端发请求时没有指定正确的
Content-Type: application/json头,Express内置的express.json()中间件只有识别到请求头标记为JSON格式时,才会解析请求体挂载到req.body上,这是req.body为空的直接原因。 - 额外参数错误:之前前端直接
JSON.stringify(tipologia)序列化字符串值,就算解析成功req.body也只会拿到part-time这个字符串,拿不到tipologia属性。 - CORS规则限制:开启
credentials: true(允许携带会话cookie)时,origin不能设为通配符*,必须指定明确的前端源地址。
修复步骤
1. 修改前端请求代码
删除请求头中错误的CORS相关字段,添加正确的Content-Type头,修正请求体传参格式:
function CreateStudyPlan(tipologia){ return new Promise((resolve, reject) => { fetch((URL+'/PianoStudio'), { method: 'POST', credentials: 'include', headers: { "Content-Type": "application/json" }, // 包装为对象传递,后端才能通过req.body.tipologia拿到值 body: JSON.stringify({ tipologia }), }).then((response) => { if (response.ok) { resolve(null); } else { response.json() .then((message) => { reject(message); }) .catch(() => { reject({ error: "Cannot parse server response." }) }); } }).catch(() => { reject({ error: "Cannot communicate with the server." }) }); }); }
2. 调整后端中间件顺序与CORS配置
CORS中间件必须放在所有其他中间件(日志、JSON解析、路由、鉴权)的最前面,否则OPTIONS预检请求会被提前拦截,触发跨域报错:
// 最先注册CORS中间件 const corsOptions = { origin: 'http://localhost:3000', credentials: true, allowedHeaders: ['Content-Type', 'Authorization'], // 明确允许Content-Type等常用请求头 methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'] // 允许预检请求的OPTIONS方法 }; app.use(cors(corsOptions)); // CORS配置完成后再注册其他中间件 app.use(morgan('dev')); app.use(express.json()); // 后续鉴权、路由代码无需修改 const isLoggedIn = (req, res, next) => { if(req.isAuthenticated()) return next(); return res.status(401).json({ error: 'not authenticated'}); } app.post('/PianoStudio', isLoggedIn, async (req, res) => { try { await dao.createPianoStudio(req.body, req.user.id); res.status(201).json(req.body); } catch(err) { console.log(err); res.status(503).json({error: `Database error during the creation of piano di studi for user ${req.user.id}.`}); } });
验证要点
- 修改完成后重启后端服务,清空浏览器缓存再发请求
- 先检查OPTIONS预检请求返回状态码为200/204,无跨域报错
- 正式POST请求的Payload格式为
{"tipologia":"part-time"},请求头携带正确的Content-Type: application/json - 服务端打印
req.body即可正常拿到结构化参数,不会为空。
内容的提问来源于stack exchange,提问作者redbite
相关产品推荐
相关产品推荐

