ExpressJS接收支付网关POST请求req.body为空,自测cURL/Insomnia正常
问题原因与解决方案
核心原因
你的本地测试发送的是application/x-www-form-urlencoded格式的POST请求,正好匹配express自带的express.urlencoded中间件的解析规则,所以可以正常拿到参数。而GPG支付网关的回调请求发送的是multipart/form-data格式的表单数据,express原生中间件不支持解析该类型的请求体,导致req.body为空。
PHP的$_POST默认同时支持解析application/x-www-form-urlencoded和multipart/form-data两种格式的POST请求,所以部署PHP文件可以正常拿到参数。
排查步骤(可选,用于确认请求类型)
先在所有解析中间件之前添加原始请求打印中间件,确认回调的请求格式:
// 放在app.use(express.json())、app.use(express.urlencoded())之前 app.use((req, res, next) => { let rawBody = ''; req.on('data', chunk => rawBody += chunk); req.on('end', () => { console.log('回调请求Content-Type:', req.headers['content-type']); console.log('回调原始请求体:', rawBody); next(); }); });
解决方案
方案1:使用multer解析multipart/form-data请求
绝大多数这类问题都是因为请求为multipart/form-data格式,使用multer中间件解析即可:
- 安装multer
npm install multer
- 改造回调路由
const multer = require('multer'); const upload = multer(); // 无文件上传,无需配置存储规则 // 用upload.none()解析纯文本表单字段 router.route('/confirm-payment-detailes').post(upload.none(), async (req,res)=>{ const {TotalAmount,PAYID,TransStatus,Signature} = req.body; console.log({TotalAmount,PAYID,TransStatus,Signature}); // 处理完业务逻辑后必须返回响应,避免网关重复回调 res.status(200).send('SUCCESS'); });
方案2:适配非常规Content-Type
如果确认请求是application/x-www-form-urlencoded格式但Content-Type头异常,修改urlencoded中间件配置,强制解析所有类型的请求体:
app.use(express.urlencoded({extended:false, type: '*/*'}));
额外注意事项
- 回调路由处理完业务逻辑后必须返回200状态码的响应,否则GPG网关会认为回调失败,多次重试推送支付结果
- 建议先完成签名校验再处理订单状态变更,避免伪造回调请求篡改订单数据
内容的提问来源于stack exchange,提问作者Rouissi Iheb
相关产品推荐
相关产品推荐

