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

Laravel 10集成Cashier Stripe Checkout需监听哪些事件?

在Laravel 10 Cashier中使用Stripe Checkout的事件监听方案(欧盟3DS场景)

针对你的培训课程预约需求,结合欧盟3DS支付要求,以下是必须监听的Stripe事件及落地建议:

核心必监听事件

  • checkout.session.completed:这是触发预约创建的核心事件。无论用户是否经过3DS验证,只有当支付完全成功、Checkout会话完成时才会触发该事件。事件中会返回payment_status: succeeded的状态,此时可以安全地为用户创建培训预约。

辅助监听事件(处理异常/边缘场景)

  • payment_intent.succeeded:作为checkout.session.completed的双重验证,确保支付意图确实完成,避免极端场景下会话状态与支付状态不一致的问题。
  • payment_intent.payment_failed:当支付失败时触发(比如3DS验证不通过、卡余额不足、卡被拒),此时需要清理用户的临时预约占位,并通知用户重新尝试支付。
  • checkout.session.async_payment_succeeded:如果支持欧盟本地异步支付方式(如Sofort),这个事件会在异步支付确认成功时触发,避免遗漏这类场景下的预约创建。
  • checkout.session.async_payment_failed:对应异步支付失败的场景,同样需要处理预约占位释放和用户通知。

Laravel Cashier中的实现步骤

  1. 配置Webhook密钥:在.env文件中设置STRIPE_WEBHOOK_SECRET,值从Stripe后台的Webhook设置中获取。
  2. 注册Webhook路由:在routes/web.php中添加:
    Route::stripeWebhooks('/stripe/webhook');
    
  3. 创建事件监听类:以处理checkout.session.completed为例,创建App\Listeners\HandleCheckoutSessionCompleted类:
    <?php
    
    namespace App\Listeners;
    
    use Laravel\Cashier\Events\WebhookReceived;
    use App\Models\User;
    use App\Models\Course;
    
    class HandleCheckoutSessionCompleted
    {
        public function handle(WebhookReceived $event)
        {
            if ($event->payload['type'] !== 'checkout.session.completed') {
                return;
            }
    
            $session = $event->payload['data']['object'];
    
            // 仅处理支付成功的会话
            if ($session['payment_status'] !== 'succeeded') {
                return;
            }
    
            // 从metadata中获取预存的用户ID和课程ID(创建Checkout会话时需存入)
            $userId = $session['metadata']['user_id'] ?? null;
            $courseId = $session['metadata']['course_id'] ?? null;
    
            if (!$userId || !$courseId) {
                // 记录日志,缺少必要数据
                logger()->error('Checkout session missing metadata', ['session_id' => $session['id']]);
                return;
            }
    
            // 幂等性处理:检查该会话是否已处理过
            if (\App\Models\CourseBooking::where('stripe_session_id', $session['id'])->exists()) {
                return;
            }
    
            // 创建培训预约
            $user = User::find($userId);
            $course = Course::find($courseId);
    
            $user->courseBookings()->create([
                'course_id' => $courseId,
                'stripe_session_id' => $session['id'],
                'status' => 'confirmed'
            ]);
    
            // 发送预约确认通知给用户
            $user->notify(new \App\Notifications\CourseBookingConfirmed($course));
        }
    }
    
  4. 注册监听器:在App\Providers\EventServiceProvider的$listen数组中添加:
    protected $listen = [
        \Laravel\Cashier\Events\WebhookReceived::class => [
            \App\Listeners\HandleCheckoutSessionCompleted::class,
            \App\Listeners\HandlePaymentIntentSucceeded::class,
            \App\Listeners\HandlePaymentIntentFailed::class,
        ],
    ];
    

关键注意事项

  • Metadata必传:创建Checkout会话时,一定要通过metadata参数传入user_id和course_id,否则Webhook事件中无法关联到具体用户和课程。
  • 幂等性保障:必须对Webhook事件做幂等处理(比如通过stripe_session_id记录已处理的会话),避免因Stripe重复发送事件导致重复创建预约。
  • 不要依赖前端跳转:success_url/cancel_url仅作为用户端的跳转提示,绝对不能用来触发预约创建逻辑——用户可能因网络问题、手动关闭页面等原因不跳转,Webhook才是可靠的服务器端通知方式。
  • 3DS自动处理:Stripe会自动处理3DS验证流程,用户完成验证后才会触发checkout.session.completed,无需额外处理3DS相关的单独事件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 10:52:54