Strapi+Stripe实操:支付成功后如何更新商品Sold字段为True?
问题描述
- 我是Strapi和Stripe初学者,正在搭建电商练习网站,需求是支付成功后将商品的
sold布尔字段设为true(商品为独款,需隐藏已售出商品)。 - 控制台无报错,但bash提示:
Updating sold status for product ID: 正确的商品ID Error updating sold boolean: Error: Model product not found - 确认
product模型确实存在,尝试过strapi.models.product但问题依旧。
订单控制器代码如下:
"use strict"; const stripe = require("stripe")(process.env.STRIPE_KEY); const { createCoreController } = require("@strapi/strapi").factories; module.exports = createCoreController("api::order.order", ({ strapi }) => ({ async create(ctx) { const { products } = ctx.request.body; try { const lineItems = await Promise.all( products.map(async (product) => { const item = await strapi .service("api::product.product") .findOne(product.id); return { price_data: { currency: "usd", product_data: { name: item.title, }, unit_amount: Math.round(item.price * 100), }, quantity: 1, }; }) ); const session = await stripe.checkout.sessions.create({ shipping_address_collection: { allowed_countries: ["US"] }, payment_method_types: ["card"], mode: "payment", success_url: process.env.CLIENT_URL + "?success=true", cancel_url: process.env.CLIENT_URL + "?success=false", line_items: lineItems, }); // Update the sold boolean to true for the purchased items const updateSoldStatus = async (productId) => { try { await strapi .query("product") .update({ id: productId }, { sold: true }); } catch (error) { console.error("Error updating sold boolean:", error); } }; // Update the sold status for each purchased product for (const product of products) { console.log(`Updating sold status for product ID: ${product.id}`); await updateSoldStatus(product.id); } await strapi .service("api::order.order") .create({ data: { products, stripeId: session.id } }); return { stripeSession: session }; } catch (error) { ctx.response.status = 500; return { error }; } }, }));
解决方案
1. 修复模型查询错误
Strapi v4中,strapi.query()需要传入完整的模型UID(即api::product.product),而非简写的product,这是你找不到模型的直接原因。同时,v4的query.update()语法也有变化,需要调整为update({ where: ... }, { data: ... })格式。
修改updateSoldStatus函数:
const updateSoldStatus = async (productId) => { try { await strapi .query("api::product.product") // 使用完整模型UID .update({ where: { id: productId } }, { data: { sold: true } }); } catch (error) { console.error("Error updating sold boolean:", error); } };
2. 修正核心逻辑错误(关键)
你当前的代码会在创建订单时立即更新商品状态,但用户可能取消支付或支付失败,导致商品被错误标记为已售出。正确做法是通过Stripe Webhook监听checkout.session.completed事件,仅在确认支付成功后更新商品状态。
步骤1:创建Stripe Webhook控制器
在Strapi中新建api::webhook.webhook控制器:
"use strict"; const stripe = require("stripe")(process.env.STRIPE_KEY); module.exports = { async stripeWebhook(ctx) { const sig = ctx.request.headers["stripe-signature"]; let event; try { event = stripe.webhooks.constructEvent( ctx.request.body, sig, process.env.STRIPE_WEBHOOK_SECRET ); } catch (err) { ctx.response.status = 400; return { error: `Webhook Error: ${err.message}` }; } // 处理支付成功事件 if (event.type === "checkout.session.completed") { const session = event.data.object; // 从元数据中取出商品ID数组 const productIds = JSON.parse(session.metadata.productIds); // 更新每个商品的sold状态 for (const productId of productIds) { await strapi.query("api::product.product").update( { where: { id: productId } }, { data: { sold: true } } ); } // 可选:更新订单状态为已支付 await strapi.query("api::order.order").update( { where: { stripeId: session.id } }, { data: { status: "paid" } } ); } ctx.response.status = 200; return { received: true }; }, };
步骤2:修改订单控制器,添加元数据
创建Stripe Session时,将商品ID存入元数据,方便Webhook获取:
const session = await stripe.checkout.sessions.create({ shipping_address_collection: { allowed_countries: ["US"] }, payment_method_types: ["card"], mode: "payment", success_url: process.env.CLIENT_URL + "?success=true", cancel_url: process.env.CLIENT_URL + "?success=false", line_items: lineItems, metadata: { productIds: JSON.stringify(products.map(p => p.id)) // 存入商品ID数组 }, });
同时删除原订单控制器中创建订单时更新sold状态的代码块。
步骤3:配置Stripe后台Webhook
在Stripe后台添加Webhook端点,URL填写你的Strapi地址+/api/webhooks/stripe-webhook,选择checkout.session.completed事件,将签名密钥存入环境变量STRIPE_WEBHOOK_SECRET。
3. 可选:使用Service更新商品
除了strapi.query(),也可以用Strapi Service更新商品,更符合最佳实践:
await strapi.service("api::product.product").update(productId, { data: { sold: true } });
内容的提问来源于stack exchange,提问作者Krisrant
相关产品推荐
相关产品推荐

