Stripe Checkout Session异常:product_data缺失、payment_intent为null
问题
使用stripe@7版本开发,调用接口创建Checkout Session时无报错,但返回结果不符合预期:
product_data未在返回的session中显示payment_intent字段为null
当前返回结果:
{"status": "success","session": {"id": "cs_test_a1mZ6W9dAO1n7IgpBkvZFJR3Uoe0TTAv3BV9U76b9JVpogcbOyImkaAvU2","object": "checkout.session","after_expiration": null,"allow_promotion_codes": null,"amount_subtotal": 99700,"amount_total": 99700,"automatic_tax": {"enabled": false,"status": null},"billing_address_collection": null,"cancel_url": "http://127.0.0.1:3000/tour/the-mountain-biker","client_reference_id": "64482b81fc72db55d5ab256c","consent": null,"consent_collection": null,"created": 1682624190,"currency": "usd","currency_conversion": null,"custom_fields": [],"custom_text": {"shipping_address": null,"submit": null},"customer": null,"customer_creation": "if_required","customer_details": {"address": null,"email": "leo@example.com","name": null,"phone": null,"tax_exempt": "none","tax_ids": null},"customer_email": "leo@example.com","expires_at": 1682710590,"invoice": null,"invoice_creation": {"enabled": false,"invoice_data": {"account_tax_ids": null,"custom_fields": null,"description": null,"footer": null,"metadata": {},"rendering_options": null}},"livemode": false,"locale": null,"metadata": {},"mode": "payment","payment_intent": null,"payment_link": null,"payment_method_collection": "always","payment_method_options": {},"payment_method_types": ["card"],"payment_status": "unpaid","phone_number_collection": {"enabled": false},"recovered_from": null,"setup_intent": null,"shipping_address_collection": null,"shipping_cost": null,"shipping_details": null,"shipping_options": [],"status": "open","submit_type": null,"subscription": null,"success_url": "http://127.0.0.1:3000/","total_details": {"amount_discount": 0,"amount_shipping": 0,"amount_tax": 0},"url": "https://checkout.stripe.com/c/pay/cs_test_a1mZ6W9dAO1n7IgpBkvZFJR3Uoe0TTAv3BV9U76b9JVpogcbOyImkaAvU2#fidkdWxOYHwnPyd1blpxYHZxWjA0SzRTa1FWQkNTSE9%2FN3BEXFF3RlJvVXJnVn02bV0yQEh8ZEJrVW01bHFPYHxqUzxtbjFBRkpdc2phMU9oUTA8NVFUU19BQXE0XGRHXHBcMTBGQH1PYUI2NTVmf1xTd0FhSicpJ2N3amhWYHdzYHcnP3F3cGApJ2lkfGpwcVF8dWAnPyd2bGtiaWBabHFgaCcpJ2BrZGdpYFVpZGZgbWppYWB3dic%2FcXdwYHgl"}}
代码(stripe@7):
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY); const Tour = require('./../models/tourModel'); const catchAsync = require('./../utils/catchAsync'); const factory = require('./handlerFactory'); const AppError = require('./../utils/appError'); exports.getCheckoutSession = catchAsync(async (req, res, next) => { //1) Get the currently booked tour const tour = await Tour.findById(req.params.tourId); //2) Create checkout session console.log(tour); const session = await stripe.checkout.sessions.create({ payment_method_types: ['card'], success_url: `${req.protocol}://${req.get('host')}/`, cancel_url: `${req.protocol}://${req.get('host')}/tour/${tour.slug}`, customer_email: req.user.email, client_reference_id: req.params.tourId, line_items: [ { quantity: 1, price_data: { currency: 'usd', unit_amount: tour.price * 100, product_data: { name: `${tour.name} Tour`, description: tour.summary, images: [`https://www.natours.dev/img/tours/${tour.imageCover}`], }, }, }, ], // metadata: { // name: `${tour.name} Tour`, // description: tour.summary, // image: `https://www.natours.dev/img/tours/${tour.imageCover}`, // }, mode: 'payment', }); //3) Create session as response res.status(200).json({ status: 'success', session, }); });
解决方案
1. product_data未显示的原因及处理
Stripe Checkout Session的返回结果中,不会直接包含product_data字段。当你通过price_data.product_data动态创建产品和价格时,Stripe会自动生成对应的Product和Price对象,但这些信息不会嵌套在Session的返回结果里。
如果需要获取产品相关信息,有两种方式:
- 调用
stripe.checkout.sessions.listLineItems(session.id)获取Session的完整商品条目,从中拿到Price ID,再调用stripe.prices.retrieve(priceId)获取价格对象,最后通过价格对象的product字段调用stripe.products.retrieve(productId)拿到产品详情。 - 提前在Stripe后台创建好Product和Price,在
line_items中直接使用price字段(而非price_data),后续可直接通过Price ID关联查询产品信息。
2. payment_intent为null的原因及处理
payment_intent为null是因为当前Session状态为open(未支付)。在Stripe的payment模式下,只有用户完成支付后,Checkout Session才会关联生成Payment Intent,此时payment_intent字段才会被赋值。
如果需要获取支付完成后的相关信息,可通过以下方式:
- 监听Stripe的
checkout.session.completedwebhook事件,用户完成支付后Stripe会推送该事件,事件中包含完整的Session信息(包括payment_intent)。 - 支付完成后,主动调用
stripe.checkout.sessions.retrieve(session.id)查询Session,此时返回的结果中会包含payment_intent字段。
当前代码中mode: 'payment'的配置是正确的,用于一次性支付场景,支付完成后Session状态会变为complete,payment_intent字段会被填充。
内容的提问来源于stack exchange,提问作者xitij
相关产品推荐
相关产品推荐

