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

如何同时使用express.json与express.raw?表单与Stripe Webhook兼容问题

解决方案

问题的核心在于:Stripe Webhook 的签名验证依赖于请求的原始字节内容,而 express.json() 中间件会将 JSON 请求体解析为 JavaScript 对象,破坏了原始数据的完整性。反之,全局使用 express.raw() 会导致其他需要 JSON 解析的路由无法正常工作。

正确的做法是只为 Stripe Webhook 路由单独应用原始数据中间件,其他路由保持使用 express.json() 处理 JSON 数据。

1. 修改 index.js 配置

移除全局的 express.raw() 中间件,仅将其绑定到 /webhooks 路由:

app.use(express.json()); // 为普通 JSON 请求保留此中间件
app.use(express.static("public"));
app.use(express.urlencoded({ extended: true }));
app.use(cors());

// 仅对 Webhook 路由应用原始数据中间件
app.post("/webhooks", express.raw({ type: "application/json" }), postStripeWebhook);

2. 修正 Webhook 处理函数

此时 req.body 是 Stripe 发送的原始 Buffer 数据,直接传入 constructEvent 即可,无需额外序列化:

export const postStripeWebhook = async (req: ExtendedRequest, res: Response) => {
    let data;
    let eventType;
    let event;
    const webhookSecret = "web hook secret provided by stripe";

    if (webhookSecret) {
        const signature = req.headers["stripe-signature"];
        try {
            // 直接使用原始 Buffer 验证签名
            event = stripe.webhooks.constructEvent(req.body, signature, webhookSecret);
        } catch (err) {
            console.log(`⚠️  Webhook signature verification failed.`);
            return res.sendStatus(400);
        }
        data = event.data;
        eventType = event.type;
    } else {
        // 无签名时,手动解析原始 Buffer 为 JSON
        const parsedBody = JSON.parse(req.body.toString());
        data = parsedBody.data;
        eventType = parsedBody.type;
    }

    let subscription;
    switch (eventType) {
        // 处理各类 Webhook 事件
    }

    res.sendStatus(200);
};

为什么这样能解决问题?

  • 普通 JSON 路由(如登录表单)依然通过 express.json() 正常解析请求体。
  • Webhook 路由通过 express.raw() 获取原始字节数据,完全匹配 Stripe 生成签名时使用的内容,确保验证通过。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 11:15:33