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

使用Deno处理Stripe Webhook时签名匹配错误排查求助

Stripe Webhook签名验证失败问题排查(Deno环境)

可能的错误原因及解决方法

1. 请求体转码导致签名计算不匹配

Stripe的Webhook签名是基于原始二进制请求体计算的,你当前将arrayBuffer转成字符串的操作可能引入编码差异,导致传递给constructEvent的payload和Stripe签名时的原始内容不一致。

解决方法:直接传递原始二进制数据,无需转码。修改代码如下:

// 移除转码步骤,直接使用Uint8Array格式的原始请求体
event = stripe.webhooks.constructEvent(
  new Uint8Array(webhookRawBody),
  webhookStripeSignatureHeader,
  stripeWebhookSecret
);

2. 请求体被重复读取

Deno中request.body是可读流,仅能读取一次。如果在调用request.arrayBuffer()之前,有其他代码先调用了request.text()、request.json()等读取方法,会导致后续读取到空数据,签名验证必然失败。

验证方式:检查代码中是否存在提前读取请求体的逻辑,确保arrayBuffer()是第一个读取请求体的操作。

3. 签名秘钥或API版本不匹配

  • 确认Stripe控制台中Webhook的签名秘钥(whsec_开头)与代码中stripeWebhookSecret完全一致,且对应正确的环境(测试/生产);
  • 确认代码中指定的apiVersion与Stripe控制台Webhook配置的API版本完全相同,版本不一致会导致签名计算逻辑差异。

确保请求体正确传递的关键要点

  • 直接使用原始二进制数据:始终将Uint8Array格式的原始请求体传递给constructEvent,避免任何转码、格式化操作;
  • 保证请求体仅读取一次:确保request.arrayBuffer()是请求体的首次读取操作,防止流被耗尽;
  • 字节级对比验证:调试时可将收到的原始二进制数据保存为文件,与Stripe控制台中对应事件的payload做字节级对比,确认内容完全一致。

修改后的完整代码示例

import "jsr:@supabase/functions-js/edge-runtime.d.ts";
import Stripe from 'https://esm.sh/stripe@11.1.0?target=deno';
import { config } from "https://deno.land/x/dotenv/mod.ts";

const env = config();
const stripeApiKey = env.STRIPE_API_KEY;
const stripeWebhookSecret = env.STRIPE_WEBHOOK_SIGNING_SECRET;

const stripe = new Stripe(stripeApiKey as string, {
  apiVersion: '2022-11-15',
  httpClient: Stripe.createFetchHttpClient(),
});

Deno.serve(async (request) => {
  const webhookStripeSignatureHeader = request.headers.get('Stripe-Signature');
  if (!webhookStripeSignatureHeader) {
    return new Response('Missing Stripe signature', { status: 400 });
  }

  const webhookRawBody = await request.arrayBuffer();
  
  let event;

  try {
    event = stripe.webhooks.constructEvent(
      new Uint8Array(webhookRawBody),
      webhookStripeSignatureHeader,
      stripeWebhookSecret
    );
  } catch (err) {
    console.error(`Webhook Error: ${err.message}`);
    return new Response(err.message, { status: 400 });
  }

  console.log(`🔔 Event received: ${event.id}`);
  return new Response(JSON.stringify({ ok: true }), { status: 200 });
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 21:53:11