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

Stripe SCA 3D Secure认证集成报错:PaymentIntent需绑定支付方式

Fixing STPPaymentHandlerErrorDomain Code=1 for Stripe SCA Compliance in iOS

我来帮你拆解这个报错的核心问题,以及对应的解决方案:

报错原因解析

你遇到的 STPPaymentHandlerErrorDomain Code=1 本质上是因为你的PaymentIntent没有关联任何PaymentMethod或Source,而STPPaymentHandler.handleNextAction()只能处理已经绑定了支付方式、需要额外SCA验证(比如3D Secure)的PaymentIntent。

在你的当前流程里,后端调用createAndConfirmPaymentIntent时没有绑定用户的PaymentMethod,导致返回的PaymentIntent处于未关联支付方式的状态,前端调用handleNextAction自然会报错。

解决方案:调整前后端流程

要解决这个问题,你需要同步调整后端的PaymentIntent创建逻辑,以及前端的调用流程:

1. 更新后端API,接收并关联PaymentMethod ID

首先,让你的createAndConfirmPaymentIntent接口新增一个参数:前端传过来的PaymentMethod ID。然后在后端创建PaymentIntent时,必须把这个PaymentMethod ID关联到PaymentIntent上,同时调用confirm(以触发SCA检查)。

举个Node.js后端的示例代码:

// 后端代码示例(Node.js + Stripe SDK)
app.post('/create-and-confirm-payment-intent', async (req, res) => {
  const { amount, paymentMethodId, returnUrl, shippingAddress } = req.body;

  try {
    const paymentIntent = await stripe.paymentIntents.create({
      amount: amount,
      currency: 'eur', // 根据你的业务调整货币类型
      payment_method: paymentMethodId, // 关键:关联前端传过来的PaymentMethod
      confirm: true, // 自动触发确认,会自动检测是否需要SCA验证
      return_url: returnUrl,
      shipping: {
        address: shippingAddress,
      },
      automatic_payment_methods: { enabled: true },
    });

    res.json({ clientSecret: paymentIntent.client_secret });
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});

2. 修改前端代码,传递PaymentMethod ID给后端

在你的iOS代码里,首先要确保你已经通过STPPaymentContext收集到了用户的PaymentMethod,然后把它的stripeId传给后端的API。修改后的前端代码如下:

// 先确认已选中PaymentMethod
guard let paymentMethod = paymentContext.selectedPaymentMethod else {
    completion(.error, NSError(domain: StripeDomain, code: 124, userInfo: [NSLocalizedDescriptionKey: "Please select a payment method first"]))
    return
}

// 调用后端API时,新增传递paymentMethod.stripeId
MyAPIClient.sharedClient.createAndConfirmPaymentIntent(
    paymentResult, 
    amount: self.paymentContext.paymentAmount,
    paymentMethodId: paymentMethod.stripeId, // 新增:传递PaymentMethod ID
    returnURL: "payments-example://stripe-redirect", 
    shippingAddress: self.paymentContext.shippingAddress, 
    shippingMethod: self.paymentContext.selectedShippingMethod
) { (clientSecret, error) in
    guard let clientSecret = clientSecret else {
        completion(.error, error ?? NSError(domain: StripeDomain, code: 123, userInfo: [NSLocalizedDescriptionKey: "Unable to parse clientSecret from response"]))
        return
    }

    // 现在调用handleNextAction,此时PaymentIntent已经绑定了PaymentMethod,可以正常处理SCA验证
    STPPaymentHandler.shared().handleNextAction(forPayment: clientSecret, authenticationContext: paymentContext, returnURL: "payments-example://stripe-redirect") { (status, handledPaymentIntent, actionError) in
        switch (status) {
        case .succeeded:
            guard let handledPaymentIntent = handledPaymentIntent else {
                completion(.error, actionError ?? NSError(domain: StripeDomain, code: 123, userInfo: [NSLocalizedDescriptionKey: "Unknown failure"]))
                return
            }
            if handledPaymentIntent.status == .requiresConfirmation {
                // 后端再次确认时,PaymentMethod已经关联,无需重复传递
                MyAPIClient.sharedClient.confirmPaymentIntent(handledPaymentIntent) { clientSecret, error in
                    guard let clientSecret = clientSecret else {
                        completion(.error, error ?? NSError(domain: StripeDomain, code: 123, userInfo: [NSLocalizedDescriptionKey: "Unable to parse clientSecret from response"]))
                        return
                    }
                    STPAPIClient.shared().retrievePaymentIntent(withClientSecret: clientSecret) { (paymentIntent, retrieveError) in
                        guard let paymentIntent = paymentIntent else {
                            completion(.error, retrieveError ?? NSError(domain: StripeDomain, code: 123, userInfo: [NSLocalizedDescriptionKey: "Unable to parse payment intent from response"]))
                            return
                        }
                        if paymentIntent.status == .succeeded {
                            completion(.success, nil)
                        } else {
                            completion(.error, NSError(domain: StripeDomain, code: 123, userInfo: [NSLocalizedDescriptionKey: "Authentication failed."]))
                        }
                    }
                }
            } else {
                completion(.success, nil)
            }
        case .failed:
            completion(.error, actionError)
        case .canceled:
            completion(.userCancellation, nil)
        }
    }
}

额外注意事项

  • 确保你的Stripe iOS SDK是最新版本,旧版本可能对SCA流程的支持有问题。
  • 后端的PaymentIntent确认逻辑里,如果遇到requires_action状态,不需要额外处理,前端的handleNextAction会自动触发3DS验证流程。
  • 测试时可以使用Stripe提供的测试卡号(比如4000000000003220)来模拟需要3DS验证的场景,确保流程正常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:38:36