基于Djstripe:确保订阅付款成功后再向客户确认订阅生效
如何在Django+Djstripe中确保Stripe订阅扣款成功后再确认给客户?
问题场景
我们在Django站点中使用Djstripe创建Stripe订阅,现有代码如下:
# Create the Stripe subscription stripe_subscription = stripe.Subscription.create( customer=customer_id, items=[{'price': plan_id}], expand=['latest_invoice.payment_intent'], metadata=metadata, ) # Sync subscription from Stripe subscription = Subscription.sync_from_stripe_data(stripe_subscription)
Stripe的订阅创建流程为:
- 创建订阅(返回200状态码)
- 生成用于扣费的支付意向(Payment Intent)
- 尝试自动扣款
- 若扣款失败,订阅状态被设为
incomplete
当前逻辑是收到步骤1的200响应后就默认付款成功,继续后续操作,但实际会出现扣款失败的情况,导致客户被错误告知订阅成功。需要实现仅当扣款实际成功时,才向客户确认订阅创建成功。
解决方案
1. 即时校验支付意向状态
由于创建订阅时已经通过expand=['latest_invoice.payment_intent']获取了关联的支付意向,可直接从返回的订阅对象中检查支付状态:
修改代码,增加状态判断逻辑:
# 创建Stripe订阅 stripe_subscription = stripe.Subscription.create( customer=customer_id, items=[{'price': plan_id}], expand=['latest_invoice.payment_intent'], metadata=metadata, ) # 提取支付意向对象 payment_intent = stripe_subscription.latest_invoice.payment_intent # 判断支付状态 if payment_intent.status == 'succeeded': # 扣款成功,同步订阅并执行后续操作(如通知客户) subscription = Subscription.sync_from_stripe_data(stripe_subscription) # 这里添加通知客户订阅成功的逻辑,比如发送邮件、更新用户状态等 elif payment_intent.status == 'requires_action': # 需要客户完成额外验证(如3DS),返回前端引导客户完成支付 # 可将payment_intent.client_secret返回给前端,调用Stripe.js完成验证 return JsonResponse({'client_secret': payment_intent.client_secret, 'status': 'requires_action'}) else: # 扣款失败,处理失败逻辑(如告知客户支付失败,取消订阅等) # 可选:主动取消incomplete状态的订阅 stripe.Subscription.cancel(stripe_subscription.id) # 这里添加通知客户支付失败的逻辑
2. 依赖Stripe Webhook处理异步支付结果
部分支付场景(如3DS验证、延迟扣款)无法即时得到结果,必须通过Webhook监听Stripe的事件来确认最终支付状态:
需监听的关键事件:
invoice.paid:发票支付成功,代表订阅扣费完成payment_intent.succeeded:支付意向执行成功invoice.payment_failed:发票支付失败,订阅会进入incomplete或past_due状态
Djstripe Webhook处理示例:
from django.http import HttpResponse from djstripe import webhooks from djstripe.models import Subscription @webhooks.handler("invoice.paid") def handle_invoice_paid(event): invoice = event.data.object subscription_id = invoice.subscription # 同步订阅状态到本地 subscription = Subscription.sync_from_stripe_id(subscription_id) # 执行订阅成功的后续操作:通知客户、激活用户权限等 # ... @webhooks.handler("invoice.payment_failed") def handle_invoice_payment_failed(event): invoice = event.data.object subscription_id = invoice.subscription # 处理支付失败逻辑:通知客户、取消订阅或引导重新支付 # ...
3. 补充注意事项
- 确保Stripe Webhook已正确配置,且签名验证开启,防止伪造事件
- 对于
requires_action的支付,前端需集成Stripe Elements完成客户验证,验证完成后Stripe会触发对应的Webhook事件 - 定期清理
incomplete状态的订阅,避免无效数据积累
内容的提问来源于stack exchange,提问作者Panos
相关产品推荐
相关产品推荐

