使用expired_card测试卡时Stripe支付无异常抛出仍成功是什么原因?
问题根因分析
- 支付流程逻辑缺失:
\Stripe\PaymentIntent::create仅用于生成支付意图对象,不会校验卡片信息有效性、也不会执行实际扣款操作。卡片过期这类卡端错误只会在调用支付确认接口、或者前端完成支付操作回传凭证校验时才会触发。当前代码创建完支付意图后直接清空购物车跳转成功页,完全跳过了实际支付校验环节,自然不会触发任何卡错误异常。 - 异常捕获规则不匹配:如果你的自定义
CardErrorException没有绑定Stripe官方抛出的\Stripe\Exception\CardException做异常转换,即使后续支付环节触发了卡片错误,也不会进入你编写的错误处理分支。 - 金额计算逻辑错误:Stripe要求传入金额的单位为对应货币的最小单位,迪拉姆(MAD)的最小单位是分,当前代码
round(Cart::total() / 100)相当于把分单位金额转成了元单位,实际传给Stripe的金额仅为预期的百分之一,同时round处理还会引发金额精度问题。
修复方案
- 调整支付流程:创建PaymentIntent获取
client_secret后传递给前端页面,前端集成Stripe Elements收集卡片信息,调用Stripe JS的confirmCardPayment方法完成支付确认,前端拿到支付结果后再回传给后端做最终状态校验。 - 补全异常捕获分支,优先捕获Stripe官方原生异常,再对接你的自定义错误处理逻辑,参考代码如下:
// 顶部导入Stripe官方异常类 use Stripe\Exception\CardException; public function store(Request $request) { $contents = Cart::content()->map(function ($item) { return $item->model->name.', '.$item->qty; })->values()->toJson(); try { \Stripe\Stripe::setApiKey('sk_test_PcRh9XreG5jbXyhCchJf9NCK00dku1xYGi'); $payment_intent = \Stripe\PaymentIntent::create([ // 修正金额计算:直接传入单位为分的整数值 'amount' => (int) Cart::total(), 'currency' => 'MAD', 'description' => 'Stripe Test Payment ddd', 'receipt_email' => $request->email, 'payment_method_types' => ['card'], 'metadata' => [ 'content' => $contents, 'quantity' => Cart::instance('default')->count(), ] ]); // 不要直接清空购物车跳转成功页,将client_secret传给前端完成后续支付操作 return view('checkout.pay', ['client_secret' => $payment_intent->client_secret]); } catch (CardException $e) { // 可在此处转换为自定义CardErrorException处理,也可直接返回错误提示 $errMsg = $e->getJsonBody()['error']['message'] ?? '您的卡片支付失败,请检查后重试'; return back()->withErrors('Error! ' . $errMsg); } catch (\Exception $e) { // 补全通用异常捕获,避免程序直接抛出未处理错误 return back()->withErrors('支付创建失败,请稍后重试'); } }
- 前端完成支付确认后,后端需要调用
PaymentIntent::retrieve接口校验支付状态为succeeded之后,再执行清空购物车、跳转成功页的操作。
内容的提问来源于stack exchange,提问作者eee aaa
相关产品推荐
相关产品推荐

