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

Stripe 3DS2支付报错:需额外操作才能完成支付的问题求助

问题与解决方案

问题背景

面向欧盟业务,采用Stripe PaymentIntent手动捕获模式(先冻结用户资金,确认请求后再扣款),多数支付场景正常,但部分用户触发报错:

"The payment attempt failed because additional action is required before it can be completed"
判断为3DS2验证要求用户在银行APP完成授权,但当前流程未自动触发该验证流程,测试卡号为4000002760003184。

核心原因

当前支付流程未正确处理Stripe PaymentIntent的requires_action状态,且前端使用了错误的交互方式(createPaymentMethod),导致3DS2验证流程未被自动触发。

解决方案

1. 重构前端支付流程(关键修复)

放弃手动创建PaymentMethod的方式,改用Stripe推荐的confirmPayment方法,该方法会自动检测并触发3DS2验证流程:

// 获取clientSecret的逻辑保持不变
const response = await axios.post(`/booking/${this.id}/payment-intent`);
const { clientSecret } = response.data;

const appearance = { theme: 'stripe' };
this.elements = stripe.elements({ appearance, clientSecret });
this.paymentElement = this.elements.create('payment', {
    fields: {
        billingDetails: {
            address: { country: 'never' },
        },
    },
});
this.paymentElement.mount('#payment-element');

// 提交支付的逻辑修改为:
async handleSubmit() {
    this.errorMessage = '';
    const { error } = await stripe.confirmPayment({
        elements: this.elements,
        confirmParams: {
            return_url: `${window.location.origin}/booking/${this.id}/success`, // 替换为你的业务成功回调地址
        },
    });

    if (error) {
        this.errorMessage = error.message;
        return;
    }
}

说明:confirmPayment会自动处理3DS2验证流程,若需用户授权,Stripe会弹出验证界面或跳转至银行APP,验证完成后重定向到指定return_url,后续可通过后端查询PaymentIntent状态完成业务逻辑。

2. 调整后端PaymentIntent创建逻辑

确保创建时启用自动支付方法,并补充必要的业务关联信息:

public function createPaymentIntent(int $id): array
{
    $bookingRequest = $this->bookingRequestSessionHandler->retrieve($id);
    $amount = $bookingRequest->total()->getMinorAmount()->toInt();
    $currency = 'eur'; // 欧盟业务建议使用欧元,可根据实际场景调整

    $options = [
        'capture_method' => 'manual',
        'currency' => $currency,
        'automatic_payment_methods' => ['enabled' => true], // 启用自动支付方法,原生支持3DS2
        'metadata' => [
            'booking_id' => $id, // 关联业务ID,便于后续查询和对账
        ],
    ];

    $payment = (new Reservation())->pay($amount, $options);

    return [
        'clientSecret' => $payment->client_secret
    ];
}

3. 后端处理PaymentIntent状态与捕获逻辑

在执行手动扣款前,需确保PaymentIntent已通过验证(状态为succeeded):

private function processPayment($paymentIntentId, $reservation): void
{
    // 先查询PaymentIntent的当前状态
    $paymentIntent = \Stripe\PaymentIntent::retrieve($paymentIntentId);
    
    if ($paymentIntent->status !== 'succeeded') {
        throw new \Exception('Payment not authenticated, cannot capture');
    }

    // 执行手动捕获操作
    $capturedPayment = \Stripe\PaymentIntent::capture($paymentIntentId, [
        'amount_to_capture' => $reservation->total()->getMinorAmount()->toInt(),
        'receipt_email' => $reservation->customer_email
    ]);
}

说明:不再需要手动传入PaymentMethodId,confirmPayment会自动完成PaymentMethod绑定与验证,后端通过PaymentIntent ID即可完成后续操作。

4. Radar规则说明

欧盟地区SCA强制要求3DS2验证,Stripe默认会根据交易风险自动触发验证流程,无需额外调整Radar规则。若存在自定义Radar规则,需检查是否有Skip 3D Secure类规则,确保此类规则仅适用于低风险、非SCA覆盖的交易场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 03:34:52