You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Swift中如何获取Stripe Token?实现Stripe支付网关并传Token至后端

实现Stripe支付网关:生成Token并传递至后端的方案

我来帮你梳理这段iOS平台上的Stripe Token生成代码,同时给你一些实用的优化建议,确保你的支付流程更稳定安全~

核心功能说明

你提供的代码是通过Stripe官方SDK,将用户输入的支付卡信息转换成安全的Token,这个Token可以安全地传递给你的后端,由后端发起实际的支付请求(永远不要直接把卡信息传给自己的后端,这是Stripe的安全合规要求)。

原始代码分析

先看你给出的实现:

private func getToken(){ 
    let cardParams = STPCardParams() 
    cardParams.number = paymentCardTextField?.cardNumber 
    cardParams.expMonth = (paymentCardTextField?.expirationMonth)! 
    cardParams.expYear = (paymentCardTextField?.expirationYear)! 
    cardParams.cvc = paymentCardTextField?.cvc 
    STPAPIClient.shared().createToken(withCard: cardParams) { (token: STPToken?, error: Error?) in 
        guard let token = token, error == nil else { 
            // Present error to user... 
            return 
        } 
        self.dictPayData["stripe_token"] = token.tokenId 
        print(self.dictPayData) 
    } 
}

这段代码的逻辑是没问题的,但有几个需要优化的点:

  • 强制解包(paymentCardTextField?.expirationMonth)!如果paymentCardTextField为空或者控件没获取到值,会直接崩溃
  • 回调里没有处理self的循环引用问题,可能导致内存泄漏
  • 错误处理部分比较简陋,用户不知道具体出了什么问题

优化后的代码实现

我调整了代码,解决了上面的问题,并且补充了错误提示和后端调用的示例:

private func getToken() {
    // 先校验输入控件和必填信息是否完整
    guard let cardTextField = paymentCardTextField,
          let cardNumber = cardTextField.cardNumber,
          let expMonth = cardTextField.expirationMonth,
          let expYear = cardTextField.expirationYear,
          let cvc = cardTextField.cvc else {
        showError(message: "请填写完整的支付卡信息")
        return
    }
    
    // 构建Stripe卡参数
    let cardParams = STPCardParams()
    cardParams.number = cardNumber
    cardParams.expMonth = expMonth
    cardParams.expYear = expYear
    cardParams.cvc = cvc
    
    // 异步请求生成Token,用weak self避免循环引用
    STPAPIClient.shared().createToken(withCard: cardParams) { [weak self] token, error in
        guard let self = self else { return }
        
        // 处理错误情况
        if let error = error {
            self.showError(message: error.localizedDescription)
            return
        }
        
        // 确保拿到有效Token
        guard let token = token else {
            self.showError(message: "Token生成失败,请重试")
            return
        }
        
        // 把Token存入数据字典,准备传给后端
        self.dictPayData["stripe_token"] = token.tokenId
        print("Token已生成:\(self.dictPayData)")
        
        // 调用后端接口传递支付数据
        self.submitPaymentDataToBackend()
    }
}

// 辅助方法:给用户展示错误提示
private func showError(message: String) {
    let alert = UIAlertController(title: "支付提示", message: message, preferredStyle: .alert)
    alert.addAction(UIAlertAction(title: "确定", style: .default))
    present(alert, animated: true)
}

// 示例:向后端传递支付数据的方法
private func submitPaymentDataToBackend() {
    // 这里替换成你的后端API地址和请求逻辑
    guard let url = URL(string: "https://your-backend-api.com/submit-payment") else { return }
    
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    
    // 把dictPayData转换成JSON数据
    do {
        let jsonData = try JSONSerialization.data(withJSONObject: dictPayData)
        request.httpBody = jsonData
        
        // 发起网络请求
        URLSession.shared.dataTask(with: request) { data, response, error in
            // 处理后端响应
            if let error = error {
                DispatchQueue.main.async {
                    self.showError(message: "网络请求失败:\(error.localizedDescription)")
                }
                return
            }
            
            // 这里可以解析后端返回的支付结果,给用户展示成功/失败提示
            DispatchQueue.main.async {
                self.showError(message: "支付请求已提交,请等待结果")
            }
        }.resume()
    } catch {
        showError(message: "数据格式错误")
    }
}

关键注意事项

  • 安全合规:永远不要将用户的卡号、CVC等敏感信息直接传给你的后端,必须通过Stripe生成Token后再传递,这能帮你规避PCI合规的复杂要求
  • SDK集成:确保你已经正确集成了Stripe iOS SDK(可以通过CocoaPods或Swift Package Manager安装),并且在项目的Info.plist中配置了网络权限
  • 错误处理:Stripe的API会返回具体的错误信息(比如卡号无效、过期日期错误等),把这些信息展示给用户,能提升支付体验
  • 内存管理:在异步回调中使用[weak self],避免循环引用导致的内存泄漏

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

火山引擎 最新活动