Stripe 3DS支付流程显示金额为0.00的技术求助
解决Stripe 3DS验证页面显示金额为0的问题
问题根源
你当前的支付流程逻辑错误:前端使用stripe.confirmCardSetup(用于预存支付方式的API)触发3DS验证,但Setup Intent本身不绑定具体支付金额,导致银行3DS页面显示0,00。而后端的charge操作在验证后执行,两者脱节导致金额无法同步到验证环节。
核心解决方案
将流程改为「直接创建支付意图(Payment Intent)并完成全流程验证」,让3DS验证环节直接关联实际支付金额。
1. 后端Laravel代码调整
修改purchase方法,先创建绑定金额的Payment Intent,返回其client_secret给前端处理验证:
public function purchase(Request $request, Plan $plan) { $user = $request->user(); $encryptedSystemId = $request->input('system_id'); $encryptedBoxId = $request->input('box_id'); // 解密并验证资源权限 $systemId = Crypt::decrypt($encryptedSystemId); $boxId = Crypt::decrypt($encryptedBoxId); $system = System::findOrFail($systemId); $box = Box::findOrFail($boxId); $total = $plan->price; try { $user->createOrGetStripeCustomer(); // 创建绑定金额的Payment Intent,强制触发3DS(符合欧洲PSD2法规) $paymentIntent = $user->createPaymentIntent([ 'amount' => $total * 100, // Stripe以分为单位计算金额 'currency' => 'eur', 'metadata' => [ 'system_id' => $systemId, 'box_id' => $boxId, 'tenant_id' => $user->tenant->id, ], 'payment_method_options' => [ 'card' => [ 'request_three_d_secure' => 'automatic', ], ], ]); // 将Payment Intent传递给前端页面 return view('your-payment-view', compact('intent', 'plan', 'system', 'box')); } catch (\Exception $exception) { return back()->with('error', 'Error processing payment: ' . $exception->getMessage()); } }
2. 前端JS代码调整
替换stripe.confirmCardSetup为stripe.confirmCardPayment,使用Payment Intent的client_secret触发验证:
<script src="https://js.stripe.com/v3/"></script> <script> let stripe = Stripe("{{ env('STRIPE_KEY') }}") let elements = stripe.elements() let style = { base: { color: '#32325d', fontFamily: '"Helvetica Neue", Helvetica, sans-serif', fontSmoothing: 'antialiased', fontSize: '16px', '::placeholder': { color: '#aab7c4' } }, invalid: { color: '#fa755a', iconColor: '#fa755a' } } let card = elements.create('card', { style: style }) card.mount('#card-element') $('.card-form').on('submit', function(e) { e.preventDefault(); $('#pay-btn').attr('disabled', true) stripe.confirmCardPayment( "{{ $intent->client_secret }}", { payment_method: { card: card, billing_details: { name: $('.card_holder_name').val() } } } ).then(function(result) { if (result.error) { toastr.error(__('rental.The data you entered contains errors! Review it and try again')) $('#pay-btn').removeAttr('disabled') } else { // 支付成功后跳转至结果页 window.location.href = "{{ route('rentals.payment-success') }}"; } }) }) </script>
3. 表单结构调整
移除冗余的payment_method隐藏字段,因为confirmCardPayment会自动处理支付方式关联:
<div class="tab-content mt-4 " id="card-tab" style="display:none"> <form class="card-form mt-3 mb-3"> @csrf <input type="hidden" name="system_id" value="{{ encrypt($system->id) }}"> <input type="hidden" name="box_id" value="{{ encrypt($box->id) }}"> <div class="mb-4"> <input class="StripeElement form-input px-4 py-3 rounded-lg w-full" name="card_holder_name" placeholder="{{ __('rental.Cardholder Name') }}"> </div> <div> <div id="card-element"></div> </div> <div id="card-errors" role="alert"></div> <div class="mt-3 text-center"> <button type="submit" class="bg-red-500 text-white font-bold py-2 px-4 rounded" id="pay-btn"> {{ __('rental.Pay') }} {{ $plan->price }} € <span class="icon" hidden><i class="fas fa-sync fa-spin"></i></span> </button> </div> </form> </div>
4. 验证调试
修改完成后,调试时确认Payment Intent的amount字段为正确的分金额(如1欧元对应100),此时3DS验证页面将显示实际支付金额,而非0,00。
内容的提问来源于stack exchange,提问作者Ahmed Habeeb
相关产品推荐
相关产品推荐

