You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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中间件解析即可:

  1. 安装multer
npm install multer
  1. 改造回调路由
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 15:24:02