Swift中如何让POST请求函数返回API响应字符串?
问题:让Swift的getPost函数返回POST请求的响应字符串
各位开发者好,我正在调用Rest API获取数据,目前已成功实现数据获取,但希望让getPost函数返回获取到的响应字符串。以下是我目前的代码:
private func getPost(one: String, two: String, link: String) { let url = URL(string: link)! var request = URLRequest(url: url) request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") request.httpMethod = "POST" let parameters: [String: Any] = [ "parent" : one, "original": two ] request.httpBody = parameters.percentEncoded() var responseString = "" print("Sarcasm \(yourMessage) \(otherMessage) \(link)") let task = URLSession.shared.dataTask(with: request) { data, response, error in guard let data = data, let response = response as? HTTPURLResponse, error == nil else { // check for fundamental networking error print("error", error ?? "Unknown error") return } guard (200 ... 299) ~= response.statusCode else { // check for http errors print("statusCode should be 2xx, but is \(response.statusCode)") print("response = \(response)") return } responseString = String(data: data, encoding: .utf8)! print("responseString = \(responseString)") // return responseString } task.resume() }
相关扩展代码:
extension Dictionary { func percentEncoded() -> Data? { return map { key, value in let escapedKey = "\(key)".addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? "" let escapedValue = "\(value)".addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? "" return escapedKey + "=" + escapedValue } .joined(separator: "&") .data(using: .utf8) } } extension CharacterSet { static let urlQueryValueAllowed: CharacterSet = { let generalDelimitersToEncode = ":#[]@" // does not include "?" or "/" due to RFC 3986 - Section 3.4 let subDelimitersToEncode = "!$&'()*+,;=" var allowed = CharacterSet.urlQueryAllowed allowed.remove(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)") return allowed }() }
我需要修改该函数,使其返回从POST请求中获取的响应字符串,而非仅打印它,但不知该如何操作。
解决方案
首先得明确:URLSession.dataTask是异步操作——函数会在网络请求完成前就执行完毕并返回,所以你不能直接用return语句返回响应字符串。我们需要用异步的方式传递结果,下面提供两种常用的可行方案:
方案1:使用闭包回调(兼容所有Swift版本)
修改函数,添加一个闭包参数来传递请求结果(成功的响应字符串或错误信息),这样就能在请求完成后拿到数据:
private func getPost(one: String, two: String, link: String, completion: @escaping (Result<String, Error>) -> Void) { // 替换强制解包,避免崩溃 guard let url = URL(string: link) else { completion(.failure(NSError(domain: "Invalid URL", code: -1, userInfo: nil))) return } var request = URLRequest(url: url) request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") request.httpMethod = "POST" let parameters: [String: Any] = [ "parent" : one, "original": two ] request.httpBody = parameters.percentEncoded() print("Sarcasm \(yourMessage) \(otherMessage) \(link)") let task = URLSession.shared.dataTask(with: request) { data, response, error in // 先处理网络层面的错误 if let error = error { completion(.failure(error)) return } // 验证HTTP响应状态码 guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else { let statusCode = (response as? HTTPURLResponse)?.statusCode ?? -1 let error = NSError(domain: "HTTP Error", code: statusCode, userInfo: ["response": response ?? "No response"]) completion(.failure(error)) return } // 解析响应数据为字符串 guard let data = data, let responseString = String(data: data, encoding: .utf8) else { completion(.failure(NSError(domain: "Invalid Response Data", code: -2, userInfo: nil))) return } print("responseString = \(responseString)") completion(.success(responseString)) } task.resume() }
使用方式:
getPost(one: "yourValue1", two: "yourValue2", link: "yourAPIUrl") { result in switch result { case .success(let responseString): // 在这里处理成功获取到的响应字符串 print("Received response: \(responseString)") case .failure(let error): // 处理请求过程中出现的错误 print("Request failed with error: \(error.localizedDescription)") } }
方案2:使用Async/Await(Swift 5.5+,iOS 15+/macOS 12+)
如果你的项目支持Swift 5.5及以上版本,用async/await会让代码更简洁易读,这也是苹果推荐的现代异步编程方式:
private func getPost(one: String, two: String, link: String) async throws -> String { guard let url = URL(string: link) else { throw NSError(domain: "Invalid URL", code: -1, userInfo: nil) } var request = URLRequest(url: url) request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") request.httpMethod = "POST" let parameters: [String: Any] = [ "parent" : one, "original": two ] request.httpBody = parameters.percentEncoded() print("Sarcasm \(yourMessage) \(otherMessage) \(link)") // 使用async/await版本的dataTask API let (data, response) = try await URLSession.shared.data(for: request) // 验证HTTP状态码 guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else { let statusCode = (response as? HTTPURLResponse)?.statusCode ?? -1 throw NSError(domain: "HTTP Error", code: statusCode, userInfo: ["response": response]) } // 解析响应字符串 guard let responseString = String(data: data, encoding: .utf8) else { throw NSError(domain: "Invalid Response Data", code: -2, userInfo: nil) } print("responseString = \(responseString)") return responseString }
使用方式:
Task { do { let responseString = try await getPost(one: "yourValue1", two: "yourValue2", link: "yourAPIUrl") // 处理成功获取的响应字符串 print("Received response: \(responseString)") } catch { // 处理请求错误 print("Request failed with error: \(error.localizedDescription)") } }
关键说明
- 异步操作无法同步返回结果,必须通过回调或异步函数的方式传递数据
- 两种方案都补充了完整的错误处理逻辑(比如无效URL、网络错误、非2xx状态码、数据解析失败),比原代码更健壮
- 原代码中
URL(string: link)!的强制解包存在崩溃风险,方案中改成了安全的可选绑定并抛出错误
内容的提问来源于stack exchange,提问作者Vaibhav Agrawal
相关产品推荐
相关产品推荐

