You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何检测用户在Stripe结账页面触发cancel_url的行为?

Stripe结账取消行为的检测方案

针对你提出的「用户未填写结账表单直接点击返回按钮触发cancel_url」的检测需求,可通过以下步骤实现:

1. 修改Cancel URL,携带Session ID

首先在创建Checkout Session时,给cancel_url添加session_id参数,这样用户取消跳转回来后,你能获取到对应的Stripe会话信息:

# 原代码修改处
cancel_url=domain + 'cancelled?session_id={CHECKOUT_SESSION_ID}',

2. 编写Cancel页面的处理视图

在你的Django项目中创建对应cancelled的视图函数,通过Session ID查询Stripe会话详情,判断用户是否有填写支付表单的行为:

def stripe_cancelled(request):
    stripe.api_key = settings.STRIPE_SECRET_KEY
    session_id = request.GET.get('session_id')
    
    # 无Session ID时直接跳转回余额页
    if not session_id:
        return HttpResponseRedirect(f'/profiles/{request.user.username}/balance/')
    
    try:
        session = stripe.checkout.Session.retrieve(session_id)
        transaction_id = session['metadata']['transactionID']
        transaction = Transaction.objects.get(id=transaction_id)
        
        # 判断用户是否未触碰支付表单:无Payment Intent或未尝试过支付
        payment_intent_id = session.get('payment_intent')
        if not payment_intent_id:
            # 完全未填写表单就取消
            transaction.status = 'cancelled_unfilled'
            print("用户未填写支付表单直接取消")
        else:
            payment_intent = stripe.PaymentIntent.retrieve(payment_intent_id)
            # 检查是否有过支付尝试
            if payment_intent['status'] == 'requires_payment_method' and not payment_intent['attempted']:
                transaction.status = 'cancelled_unfilled'
                print("用户未提交支付表单就取消")
            else:
                # 用户填写了表单但取消,标记为普通取消
                transaction.status = 'cancelled'
        
        transaction.save()
        # 可添加通知逻辑
        add_notification(request.user, 'payment_cancelled', 'balance')
        
    except (stripe.error.StripeError, Transaction.DoesNotExist):
        # 处理异常,直接跳转
        pass
    
    return HttpResponseRedirect(f'/profiles/{request.user.username}/balance/')

3. 补充Webhook监听超时场景

除了用户主动点击取消,还需处理「用户打开结账页面后未操作超时」的情况,在Webhook中监听checkout.session.expired事件:

def stripe_webhook(request):
    # 原有代码...
    
    # Handle the checkout.session.completed event
    if event['type'] == 'checkout.session.completed':
        # 原有成功逻辑...
    
    # 新增超时事件处理
    elif event['type'] == 'checkout.session.expired':
        session = event['data']['object']
        try:
            userObject = User.objects.get(username=session['client_reference_id'])
            transaction = Transaction.objects.get(id=session['metadata']['transactionID'])
            transaction.status = 'expired'
            transaction.save()
            add_notification(userObject, 'payment_expired', 'balance')
        except (User.DoesNotExist, Transaction.DoesNotExist):
            pass
    
    return HttpResponse(status=200)

核心判断逻辑说明

  • 无Payment Intent:用户打开结账页面后完全未触碰支付表单,Stripe不会生成Payment Intent
  • Payment Intent未尝试支付:用户可能填写了部分表单但未提交支付,此时attempted字段为False,状态为requires_payment_method

内容的提问来源于stack exchange,提问作者vladimir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 01:53:15