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

Stripe集成Express无法获取raw body导致webhook签名校验失败

问题原因

该问题的核心诱因是全局JSON解析中间件优先级高于路由级raw请求体解析中间件:
如果你在代码中提前全局注册了express.json(),该中间件会在匹配到/stripe_webhook路由前,就把所有Content-Type: application/json的请求体解析为JavaScript对象,后续路由上配置的express.raw()不会重复处理已经被解析过的请求,因此你拿到的request.body始终是JSON对象而非原始Buffer格式,直接导致Stripe签名校验不通过。

修复方案
  • 方案1(推荐,改动成本最低):调整中间件和路由的注册顺序,将Stripe webhook路由移动到全局express.json()注册之前,保证webhook请求优先被raw解析器处理:
// 第一步:优先注册Stripe webhook路由,使用raw解析
router.post(
  "/stripe_webhook",
  express.raw({ type: "application/json" }),
  (request, response) => {
    updateStripePaymentStatus(request, response);
  }
);

// 第二步:再注册全局JSON解析中间件,供其他普通业务接口使用
app.use(express.json());

// 第三步:注册其余普通业务路由
// app.use('/api/order', orderRouter)
// ...其他路由
  • 方案2:修改全局JSON解析中间件的逻辑,对Stripe webhook路径直接跳过解析:
app.use((req, res, next) => {
  // webhook路径跳过JSON解析,交给路由级的raw解析器处理
  if (req.path === "/stripe_webhook") {
    return next();
  }
  // 其余路径正常走JSON解析
  express.json()(req, res, next);
});
  • 现有代码的额外问题修复:
    1. 签名校验失败的catch分支中,返回400响应后需要加return终止逻辑,否则代码会继续向下执行,在event为undefined时触发switch逻辑报错:
    try {
      event = stripe.webhooks.constructEvent(request.body, sig, endpointSecret);
    } catch (err) {
      console.log(err);
      // 加return终止后续逻辑执行
      return response.status(400).send(`Webhook Error: ${err.message}`);
    }
    
    1. 数据库save()操作前需要加await,同时补全查询为空的判断,避免异步逻辑未执行完就返回响应、或者查询不到文档时触发空指针报错:
    case "payment_intent.succeeded":
      const paymentIntent = event.data.object;
      const doc = await FileModel.findOne({ paymentId: paymentIntent.id });
      if (!doc) {
        return response.status(404).send('Matching payment record not found');
      }
      doc.paymentStatus = paymentIntent.status;
      // 加await等待保存完成
      await doc.save();
      break;
    

内容的提问来源于stack exchange,提问作者user18472307

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 05:12:16