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

部署在Vercel的Next.js项目Stripe webhook端点请求被拒、签名校验失败怎么办?

问题原因

  • 环境/配置不匹配:本地用的是Stripe CLI生成的测试签名密钥,生产环境需要用Stripe后台对应Webhook生成的独立签名密钥,两者不一致会直接导致校验失败;另外如果Stripe后台填写的Webhook地址是HTTP协议,Vercel会自动重定向到HTTPS,跳转过程会丢失原始请求体和签名头。
  • 请求流被提前消费:如果项目配置了全局中间件middleware.ts,且中间件内有读取请求体的操作,会导致API路由拿到的请求流为空;部分CORS、请求解析类的中间件也会自动解析并修改原始请求体,破坏签名所需的原始内容。
  • 平台差异:Vercel Serverless Function的运行环境和本地开发环境的请求处理逻辑存在差异,手动读取请求流的逻辑在部分场景下会拿到异常内容。

解决方案

  • 校验基础配置
    1. 登录Stripe后台,打开生产环境Webhook配置页,复制Signing secret值,确认Vercel项目环境变量中存储的webhookSecret和该值完全一致,修改环境变量后需要重新部署项目生效。
    2. 确认Stripe后台填写的Webhook地址是完整的HTTPS地址,格式为https://你的部署域名/api/stripe/webhooks,避免触发Vercel的自动跳转。
  • 移除不必要的中间件
    Stripe Webhook调用属于服务器端请求,不会触发浏览器CORS预检,直接删除现有CORS配置即可,避免CORS库修改原始请求体。同时检查全局中间件middleware.ts,删除所有消费请求体的逻辑(比如request.json()、request.text()调用)。
  • 适配Vercel的原始请求体获取逻辑
    Vercel会自动将未解析的原始请求体挂载到req.rawBody属性上,优先使用该属性获取原始内容,同时兼容本地开发环境的手动buffer逻辑,修改后的代码如下:
    const webhookHandler = async (req: NextApiRequest, res: NextApiResponse) => {
      if (req.method === 'POST') {
        // 优先读取Vercel注入的原始body, fallback到手动读取适配本地环境
        const rawBody = (req.rawBody as Buffer) ?? await buffer(req)
        const sig = req.headers['stripe-signature'] as string
    
        let event: Stripe.Event
        try {
          event = stripe.webhooks.constructEvent(rawBody.toString(), sig, webhookSecret)
        } catch (err) {
          console.log(`❌ Error message: ${err.message}`)
          res.status(400).send(`Webhook Error: ${err.message}`)
          return
        }
        // 保留原有业务逻辑
      }
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 14:18:02