如何在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
相关产品推荐
相关产品推荐

