使用Bun + Hono处理Stripe Webhook签名时解析事件失败求助
解决Bun+Hono环境下Stripe Webhook签名验证失败问题
核心问题排查与修复方案
1. 错误适配Cloudflare专属Crypto Provider
你当前代码中使用的Stripe.createSubtleCryptoProvider()是Cloudflare Worker环境的专属适配,而Bun本身内置标准Web Crypto API,无需额外指定该Provider。移除这个参数即可让Stripe SDK自动适配Bun环境:
修改constructStripeEvent函数:
async function constructStripeEvent(body: string, sig: string) { try { let event = await stripe.webhooks.constructEventAsync( body, sig, config.stripe.webhookSecret // 移除最后两个参数:undefined和Stripe.createSubtleCryptoProvider() ); return event; } catch (error) { log.error(error); return { error }; } }
2. 确保请求体完整性
Stripe签名验证要求原始请求体字节完全一致,若Hono中间件提前解析或修改了请求体编码,会直接导致验证失败:
- 检查全局/路由组是否启用
bodyParser之类的中间件,webhook路由需跳过这类处理 - 保持
await c.req.text()的写法,同时将body的类型从any改为string,避免类型隐式转换问题
3. 验证Webhook密钥正确性
确认config.stripe.webhookSecret是Stripe Dashboard对应Webhook端点的签名密钥(格式为whsec_xxx开头),而非普通API密钥,密钥不匹配是签名失败的常见原因。
4. 本地测试的转发一致性
若使用ngrok等工具本地开发,需保证Stripe Dashboard配置的Webhook URL与转发地址完全一致;测试事件必须从Stripe Dashboard发送,手动构造的请求体易出现编码差异导致验证失败。
修复后完整代码示例
// POST /stripe/webhook stripe.post("/webhook", async (c) => { const body = await c.req.text(); const sig = c.req.raw.headers.get("stripe-signature"); if (!sig) { return c.json({ error: "No signature" }, 401); } const event = await constructStripeEvent(body, sig); if (event.error) { c.status(400); return c.json({ error: "Invalid signature", detail: event.error.message }); } log.info({ event }); return c.json({ message: "ok" }); }); // construct wh event async function constructStripeEvent(body: string, sig: string) { try { const event = await stripe.webhooks.constructEventAsync( body, sig, config.stripe.webhookSecret ); return { event }; // 统一成功/失败返回结构,便于后续判断 } catch (error) { log.error("Webhook签名验证失败:", error); return { error: error as Error }; } }
内容的提问来源于stack exchange,提问作者dickey
相关产品推荐
相关产品推荐

