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

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 }} &euro; 
                <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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 09:57:02