
stripe 的 custom_fields 不适用于商品规格选择和库存管理;应通过独立 product/price 建模变体,并由业务后端自行实现库存校验与扣减逻辑。
stripe 的 custom_fields 不适用于商品规格选择和库存管理;应通过独立 product/price 建模变体,并由业务后端自行实现库存校验与扣减逻辑。
在 Next.js 电商项目中集成 Stripe 时,开发者常误将 custom_fields 视为商品属性(如 T 恤尺码)的选择入口。但需明确:Stripe Checkout 的 custom_fields 是用于收集支付附带的元数据(如 Discord 用户名、企业发票号),而非定义商品变体或驱动库存逻辑。将其用于尺寸选择,不仅破坏用户体验(用户在结算页而非商品页做关键决策),更因 Stripe 缺乏原生库存能力,导致库存超卖风险无法规避。
✅ 正确架构:用独立 Price 建模变体
每个可售组合(如 “T 恤 - Small”、“T 恤 - Medium”)应对应唯一的 Stripe Product + Price 对。例如:
// 创建三个独立 Price(均关联同一 Product 或不同 Product)
const smallPrice = await stripe.prices.create({
product: 'prod_tshirt_basic', // 或新建 prod_tshirt_small
unit_amount: 2999,
currency: 'usd',
nickname: 'T-Shirt (Small)',
});
const mediumPrice = await stripe.prices.create({
product: 'prod_tshirt_basic',
unit_amount: 2999,
currency: 'usd',
nickname: 'T-Shirt (Medium)',
});前端商品页即可直接渲染这些 Price ID,并在添加购物车时绑定具体变体。Checkout Session 仅需传入已选 Price ID:
const session = await stripe.checkout.sessions.create({
mode: 'payment',
line_items: [{
price: selectedPriceId, // 如 'price_1Qx...'(对应 Medium)
quantity: 1,
}],
success_url: `${origin}/success`,
cancel_url: `${origin}/cart`,
});⚠️ 库存控制必须由你完全接管
Stripe 不提供任何库存(inventory)功能。所有库存状态(总库存、预占库存、已售出量)必须在你的数据库中维护,并在关键路径严格校验:
- 加购前:检查 size=medium 的实时可用库存 ≥ 1
- 创建 Checkout Session 前:再次校验(防止并发冲突)
- 支付成功后(Webhook payment_intent.succeeded):原子性扣减库存
- 支付失败或取消(checkout.session.expired / payment_intent.payment_failed):释放预占库存
示例库存校验伪代码(Next.js API Route):
// POST /api/create-checkout-session
export async function POST(req: Request) {
const { priceId, quantity } = await req.json();
// 1. 查询该 priceId 对应的库存余量(需映射 price → size → stock)
const inventory = await db.inventory.findUnique({
where: { priceId },
});
if (!inventory || inventory.available < quantity) {
return Response.json(
{ error: 'Insufficient stock' },
{ status: 400 }
);
}
// 2. 创建 Session(此时库存未扣减,仅校验)
const session = await stripe.checkout.sessions.create({ /* ... */ });
return Response.json({ url: session.url });
}? 关键注意事项
- 不要依赖 custom_fields 传递业务逻辑:它无法触发库存变更,也无法在 Webhook 中可靠映射到商品维度。
- Price ID 是唯一可信标识:所有库存、日志、报表均应基于 Price ID(而非自定义字段值)进行关联。
- 预占机制不可省略:用户加入购物车即应预占库存(如 Redis 键 cart:${userId}:stock:${priceId}),避免“看到有货却下单失败”。
- Webhook 必须幂等处理:payment_intent.succeeded 可能重复投递,库存扣减需使用数据库 UPDATE ... WHERE available >= $quantity 并检查影响行数。
归根结底,Stripe 是支付管道,不是商品目录或库存系统。将变体建模为独立 Price,并由你的应用层承担库存状态管理,是当前最健壮、可扩展且符合 Stripe 设计哲学的实践方案。










