Laravel中如何通过Payment Intent验证Stripe支付的卡余额不足或拒付?
解决方案:Stripe Payment Intent 测试卡错误未触发的问题
你的核心问题在于使用了Stripe已弃用的Token创建流程,且在确认Payment Intent阶段未正确捕获支付失败的同步/异步错误。以下是具体修复步骤:
1. 替换Token创建流程为Stripe Elements(官方推荐)
Stripe不再建议手动创建Token,改用Elements组件(或Payment Element)收集卡信息,既能安全处理敏感数据,也能自动覆盖更多前端验证场景,包括测试卡的错误判断。
Laravel后端调整
移除创建Token的代码,直接生成Payment Intent并返回客户端密钥:
// 创建Payment Intent(仅需设置金额、货币) $paymentIntent = \Stripe\PaymentIntent::create([ 'amount' => 1000, // 单位:分 'currency' => 'usd', 'automatic_payment_methods' => ['enabled' => true], ]); // 返回客户端密钥给前端用于支付确认 return response()->json(['clientSecret' => $paymentIntent->client_secret]);
2. 前端捕获Payment Intent确认阶段的错误
测试卡的余额不足、挂失等错误,均在确认Payment Intent阶段触发,需在前端支付确认逻辑中捕获并反馈给用户:
前端示例(JavaScript + Stripe.js)
// 初始化Stripe及Elements const stripe = Stripe('你的Stripe公钥'); const elements = stripe.elements(); const cardElement = elements.create('card'); cardElement.mount('#card-element'); // 支付提交按钮事件 document.getElementById('submit-payment').addEventListener('click', async () => { const { error } = await stripe.confirmCardPayment( '后端返回的clientSecret', { payment_method: { card: cardElement, billing_details: { name: '用户姓名', }, }, } ); if (error) { // 捕获测试卡错误并提示用户 alert(error.message); } else { // 支付成功后跳转或更新页面状态 window.location.href = '/payment-success'; } });
3. 配置Webhook处理异步支付结果
部分测试卡场景(如需要3DS验证的卡)会触发异步支付结果,必须通过Stripe Webhook接收payment_intent.succeeded和payment_intent.payment_failed事件,更新本地订单状态:
Laravel Webhook路由
Route::post('/stripe/webhook', [StripeWebhookController::class, 'handle']);
Webhook控制器逻辑
public function handle(Request $request) { $payload = $request->getContent(); $sigHeader = $request->header('Stripe-Signature'); $webhookSecret = config('services.stripe.webhook_secret'); try { $event = \Stripe\Webhook::constructEvent( $payload, $sigHeader, $webhookSecret ); } catch (\UnexpectedValueException $e) { return response()->json(['error' => '无效请求'], 400); } catch (\Stripe\Exception\SignatureVerificationException $e) { return response()->json(['error' => '无效签名'], 400); } // 处理支付成功事件 if ($event->type === 'payment_intent.succeeded') { $paymentIntent = $event->data->object; Order::where('stripe_payment_intent_id', $paymentIntent->id)->update(['status' => 'paid']); } // 处理支付失败事件 if ($event->type === 'payment_intent.payment_failed') { $paymentIntent = $event->data->object; Order::where('stripe_payment_intent_id', $paymentIntent->id)->update([ 'status' => 'failed', 'error_message' => $paymentIntent->last_payment_error->message ?? '支付失败' ]); } return response()->json(['status' => 'success']); }
4. 测试验证
使用Stripe测试卡验证:
- 余额不足:
4000 0000 0000 0002 - 挂失卡:
4000 0000 0000 0044 - 需3DS验证:
4000 0000 0000 3220
此时前端会在confirmCardPayment时捕获错误提示,后端Webhook也会同步接收失败事件,确保系统正确触发错误反馈并更新订单状态。
内容的提问来源于stack exchange,提问作者Shams
相关产品推荐
相关产品推荐

