Swift发送带JSON Body的POST请求对接Stripe后端服务问题排查
问题排查及修复方案
- 参数类型不匹配:你代码中
parameters字典的price字段值为字符串"50",接口要求传入数字类型50,类型错误会直接导致服务端参数解析失败。 - JSON序列化无异常处理:使用
try?进行JSON序列化会忽略所有序列化错误,一旦序列化失败会得到空的jsonData,导致请求无有效Body。 - Content-Length头设置错误:对可选类型的
jsonData?.count使用String(describing:)格式化,会生成带Optional()标识的非法值,不符合HTTP头规范。实际上URLSession会自动根据httpBody计算Content-Length,无需手动设置该头字段。 - 控件逻辑不一致:代码开头禁用的是
checkoutButton,请求成功后启用的是buyButton,如果为同一控件会导致按钮始终无法点击,需确认控件命名对应关系。 - 无错误日志定位:当前代码无任何错误打印逻辑,请求失败、返回值解析失败时直接静默返回,无法定位具体错误原因。
修正后代码
override func viewDidLoad() { super.viewDidLoad() checkoutButton.addTarget(self, action: #selector(didTapCheckoutButton), for: .touchUpInside) checkoutButton.isEnabled = false // 修正:price改为数字类型,符合接口要求 let parameters: [String: Any] = [ "price": 50 ] // 修正:使用do-catch处理序列化异常,避免得到空Body do { let jsonData = try JSONSerialization.data(withJSONObject: parameters) var request = URLRequest(url: backendCheckoutUrl) request.httpMethod = "POST" // 修正:删除手动设置Content-Length,由系统自动计算 request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.httpBody = jsonData let task = URLSession.shared.dataTask(with: request, completionHandler: { [weak self] (data, response, error) in // 新增:先打印错误和响应状态码,方便定位问题 if let error = error { print("请求错误:\(error.localizedDescription)") return } if let httpResponse = response as? HTTPURLResponse { print("响应状态码:\(httpResponse.statusCode)") } if let data = data, let responseStr = String(data: data, encoding: .utf8) { print("服务端返回内容:\(responseStr)") } guard let self = self, let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String : Any], let customerId = json["customer"] as? String, let customerEphemeralKeySecret = json["ephemeralKey"] as? String, let paymentIntentClientSecret = json["paymentIntent"] as? String, let publishableKey = json["publishableKey"] as? String else { print("返回参数解析失败") return } STPAPIClient.shared.publishableKey = publishableKey var configuration = PaymentSheet.Configuration() configuration.merchantDisplayName = "Example, Inc." configuration.applePay = .init( merchantId: "com.foo.example", merchantCountryCode: "US" ) configuration.customer = .init( id: customerId, ephemeralKeySecret: customerEphemeralKeySecret ) configuration.returnURL = "....." configuration.allowsDelayedPaymentMethods = true self.paymentSheet = PaymentSheet( paymentIntentClientSecret: paymentIntentClientSecret, configuration: configuration ) DispatchQueue.main.async { // 修正:统一控件命名,和开头的checkoutButton保持一致 self.checkoutButton.isEnabled = true } }) task.resume() } catch { print("JSON序列化失败:\(error.localizedDescription)") } }
额外排查建议
如果修改后仍然无法正常运行,可以根据控制台打印的状态码、返回内容判断问题:
- 状态码400:参数仍然不符合服务端要求,核对参数名、参数类型是否和接口要求完全一致
- 状态码401/403:接口有权限校验,检查是否需要携带token等鉴权信息
- 状态码500:服务端内部错误,联系后端人员排查服务端逻辑
内容的提问来源于stack exchange,提问作者Tarik SLIMANI
相关产品推荐
相关产品推荐

