Swift中如何使用字符串格式证书发起REST API POST请求
解决带PEM格式客户端证书的POST请求问题
你的核心问题是PEM格式的证书字符串包含非Base64内容,导致解码失败。以下是完整的解决步骤:
1. 清理PEM证书字符串
PEM证书里的-----BEGIN CERTIFICATE-----、-----END CERTIFICATE-----标记和换行符都不属于Base64编码内容,必须先移除:
let rawPemString = """ -----BEGIN CERTIFICATE----- MIID9jCCAt6gAwIBAgIQNwHqBnL+445eqCUKVWroxDANBgkqhkiG9w0BAQsFADCB XufZCQ4mDV3MU0z+wsS4alR7b410V5Wet36pjUkrWtHEI2dBWZFzCOay19Vpb2V2 0M/zl07YpoZYxw== -----END CERTIFICATE----- """ // 清理无关内容,只保留纯Base64字符串 let cleanedCertString = rawPemString .replacingOccurrences(of: "-----BEGIN CERTIFICATE-----", with: "") .replacingOccurrences(of: "-----END CERTIFICATE-----", with: "") .replacingOccurrences(of: "\n", with: "") .trimmingCharacters(in: .whitespacesAndNewlines)
2. 将清理后的字符串转为Data
现在可以正常进行Base64解码:
guard let certData = Data(base64Encoded: cleanedCertString) else { // 替换为你的错误处理逻辑 print("证书Base64解码失败") return }
3. 创建SecCertificate对象
用解码后的Data生成系统可识别的证书对象:
guard let clientCert = SecCertificateCreateWithData(nil, certData as CFData) else { print("生成SecCertificate失败") return }
4. 配置URLSession以使用客户端证书
需要自定义代理处理服务器的证书验证请求,提供客户端证书:
class CertAuthDelegate: NSObject, URLSessionDelegate { private let clientCertificate: SecCertificate init(cert: SecCertificate) { self.clientCertificate = cert super.init() } func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { // 仅处理客户端证书验证挑战 guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate else { completionHandler(.performDefaultHandling, nil) return } // 创建包含客户端证书的凭证 let credential = URLCredential( certificate: clientCertificate, persistent: false ) completionHandler(.useCredential, credential) } }
5. 发起POST请求
用配置好的URLSession发送请求:
// 初始化代理和Session let authDelegate = CertAuthDelegate(cert: clientCert) let session = URLSession(configuration: .default, delegate: authDelegate, delegateQueue: .main) // 构建请求 guard let endpointURL = URL(string: "https://your-target-endpoint.com") else { print("无效的端点URL") return } var postRequest = URLRequest(url: endpointURL) postRequest.httpMethod = "POST" postRequest.setValue("application/json", forHTTPHeaderField: "Content-Type") // 设置请求体(根据实际需求调整) let requestBody = ["param1": "value1", "param2": "value2"] do { postRequest.httpBody = try JSONSerialization.data(withJSONObject: requestBody) } catch { print("构建请求体失败:\(error)") return } // 发送请求 let task = session.dataTask(with: postRequest) { data, response, error in if let error = error { print("请求出错:\(error.localizedDescription)") return } guard let httpResp = response as? HTTPURLResponse, (200...299).contains(httpResp.statusCode) else { print("请求返回错误状态码") return } if let responseData = data, let respString = String(data: responseData, encoding: .utf8) { print("请求成功,返回内容:\(respString)") } } task.resume()
额外说明
- 如果证书链包含多个证书(如客户端证书+中间证书),需要分别清理每个证书字符串,生成对应的
SecCertificate数组,然后用URLCredential(certificates: [clientCert, intermediateCert], persistent: false)创建凭证 - 替换代码中的端点URL、请求体内容为实际业务数据
- 上线代码请替换示例中的
print为正式的错误处理逻辑
内容的提问来源于stack exchange,提问作者Azeem Muzammil
相关产品推荐
相关产品推荐

