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

如何在Stripe支付成功后将商品数据保存至数据库?

支付成功后获取商品并保存到数据库的实现方案

你需要通过以下步骤在payment_intent.succeeded事件中获取订单商品并写入数据库:

核心思路

payment_intent.succeeded事件本身不直接包含订单商品(line_items),需要通过关联的Checkout Session拉取商品数据——因为你是通过Stripe Checkout创建的支付流程,每个支付意图都会绑定对应的Checkout Session。

具体实现步骤

1. 将Webhook处理函数改为异步

调用Stripe API和数据库操作都是异步任务,需要把webhook的回调函数标记为async。

2. 从支付意图中获取关联的Checkout Session ID

通过paymentIntent.checkout_session字段可以拿到当前支付对应的Checkout Session唯一ID。

3. 查询Checkout Session并展开商品列表

使用Stripe的checkout.sessions.retrieve方法查询Session,同时通过expand: ["line_items"]参数强制返回完整的商品数据(默认不返回line_items)。

4. 提取商品数据并写入数据库

把获取到的line_items转换为适配你数据库的格式,执行插入操作即可。

修改后的Webhook代码

app.post(
  "/webhook",
  express.raw({ type: "application/json" }),
  async (request, response) => {
    const sig = request.headers["stripe-signature"];
    let event;
    try {
      event = stripe.webhooks.constructEvent(request.body, sig, endpointSecret);
    } catch (err) {
      response.status(400).send(`Webhook Error: ${err.message}`);
      return;
    }

    switch (event.type) {
      case "payment_intent.succeeded":
        const paymentIntent = event.data.object;
        
        // 获取关联的Checkout Session ID
        const checkoutSessionId = paymentIntent.checkout_session;
        if (!checkoutSessionId) {
          console.log("当前支付意图未关联Checkout Session");
          response.status(200).send();
          return;
        }

        try {
          // 查询Checkout Session并展开line_items
          const session = await stripe.checkout.sessions.retrieve(checkoutSessionId, {
            expand: ["line_items"]
          });

          // 提取商品数据,适配你的数据库结构
          const orderItems = session.line_items.data.map(item => ({
            productName: item.price.product.name,
            unitPrice: item.price.unit_amount / 100, // 转换为美元(Stripe以分为单位存储金额)
            quantity: item.quantity,
            productImage: item.price.product.images[0] || null,
            paymentIntentId: paymentIntent.id,
            checkoutSessionId: checkoutSessionId,
            createdAt: new Date()
          }));

          // 替换为你的数据库插入逻辑(示例为MongoDB批量插入)
          // await OrderModel.create({ items: orderItems, paymentIntentId: paymentIntent.id });
          console.log(`成功保存${orderItems.length}件商品到数据库`);

        } catch (error) {
          console.error("保存商品到数据库失败:", error);
          // 即使保存失败,也返回200避免Stripe重复发送webhook
        }
        break;
      default:
        console.log(`未处理的事件类型: ${event.type}`);
    }

    // 必须返回200状态码告知Stripe事件已处理
    response.status(200).send();
  }
);

关键注意事项

  • 幂等性处理:webhook可能因网络问题重复发送,建议用paymentIntent.id作为订单唯一标识,避免重复插入相同数据。
  • 字段适配:根据你创建Checkout Session时的参数调整商品字段提取逻辑,比如若设置了description,可替换为item.description。
  • 异步错误处理:所有异步操作(Stripe API调用、数据库操作)都要包裹try/catch,避免webhook因未处理错误返回非200状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 06:20:34