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

Stripe Webhook签名验证失败:未找到匹配预期载荷的签名

Stripe Webhook签名验证失败问题排查与解决

我在用Stripe创建结账会话,会话完成时Webhook能触发,但一直收到错误:

"error": "No signatures found matching the expected signature for payload. Are you passing the raw request body you received from Stripe?"

已确认Webhook签名密钥正确,试过express.raw({type: 'application/json'})、bodyParser.raw(),还加了自定义中间件,都没解决问题。

我的当前代码

主路由代码

const stripeRouter = express.Router({ mergeParams: true });

const endPointSecret = 'Webook_Secret'

stripeRouter.post('/webhook',
express.raw({type: 'application/json'}),
async (req: express.Request, res: express.Response) => {
  const stripe = await getStripe();
  await getStripeSecretKey();

  const sig = req.headers['stripe-signature'];
  console.log(`signature: ${sig}`)
  const payload = req.body;
  console.log(`payload: ${payload}`)

    let eventType;
    let data;

  if (endPointSecret) {
    let event;
    try {
      event = stripe.webhooks.constructEvent(payload, sig, endPointSecret);
      console.log(`$$$$$ Webhook Verification Successful`)
    } catch (err) {
      console.log(`$$$$$ Webhook signature verification failed`, err.message)
      res.status(400).json({error: err.message, signature: req.body});
      return;
    }

    eventType = event.type;
    data = event.data;
    console.log(`$$$ EVENT TYPE: ${eventType}`)
    console.log(`$$$ DATA: ${data}`)
  } else {
    data = req.body.data.object;
    eventType = req.body.type;
  }
})

尝试过的自定义中间件

stripeRouter.use((req: express.Request, res: express.Response, next: express.NextFunction) => {
  if (req.originalUrl === '/webhook') {
    next();
  } else {
    express.json()(req, res, next);
  }
})

排查与解决步骤

  • 优先排查全局中间件干扰:检查你的Express应用是否在全局级别注册了express.json()或bodyParser.json(),这类中间件会提前解析请求体,破坏Stripe签名验证依赖的原始请求数据。要确保webhook路由在这些全局中间件之前注册,或者通过配置排除webhook路径。
  • 验证签名头完整性:打印sig值,确认它是完整的Stripe签名格式(类似t=1690000000,v1=abcdef123456,v0=ghijkl789012),如果是undefined或截断状态,检查反向代理(Nginx、Cloudflare等)是否传递了所有Stripe请求头。
  • 锁定签名密钥环境:确认endPointSecret是Stripe Dashboard对应Webhook端点的签名密钥,且区分测试/生产环境,不要和API密钥混淆。
  • 强制保留原始请求体:修改express.raw配置,手动保存原始Buffer到请求对象,避免中间件隐式转换:
    express.raw({
      type: 'application/json',
      verify: (req, res, buf) => {
        (req as any).rawBody = buf;
      }
    })
    
    之后用req.rawBody作为constructEvent的payload参数。
  • 提前初始化Stripe客户端:不要在请求处理函数里异步获取Stripe实例和密钥,建议在应用启动时完成初始化,避免验证时客户端未就绪的问题。
  • 用Stripe CLI测试:通过stripe listen --forward-to localhost:3000/webhook转发测试事件,CLI会自动生成合法签名,快速定位是代码问题还是生产环境网络/代理问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 15:02:02