URLSession dataTask返回0字节数据问题排查求助
我来帮你梳理几个大概率导致这个问题的原因,结合你的代码来看:
1. 请求参数/方法未正确处理(最可能的原因)
你的简易Alamofire实现里,参数只是被存在结构体里,根本没有编码到请求中。比如如果是POST请求,你没有把parameters转换成HTTP Body,也没设置对应的Content-Type请求头;如果是GET请求,参数也没有拼接到URL上。
服务器因为没有收到预期的参数,可能会返回空数据,但这属于业务层面的“空响应”,不是网络错误,所以URLSession的error会是nil。而你在Playground里的请求应该是直接配置了完整的URL(GET参数已拼接)或正确设置了请求体(POST),所以能拿到数据。
修复建议:
修改Alamofire.request的初始化方法,添加参数编码逻辑:
init(_ url: URL, method: Alamofire.Method? = .get, parameters: Parameters? = nil, headers: Headers? = nil) { self.url = url var urlRequest = URLRequest(url: url) urlRequest.httpMethod = method?.rawValue ?? "GET" // 处理参数编码 if let parameters = parameters { if method == .post { // JSON编码(根据你的服务器要求选择编码方式,比如form-urlencoded) do { urlRequest.httpBody = try JSONSerialization.data(withJSONObject: parameters) urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type") } catch { print("参数JSON编码失败:\(error)") } } else if method == .get { // GET参数拼接 var components = URLComponents(url: url, resolvingAgainstBaseURL: true) components?.queryItems = parameters.compactMap { key, value in guard let val = value else { return nil } return URLQueryItem(name: key, value: "\(val)") } if let encodedUrl = components?.url { urlRequest.url = encodedUrl } } } // 自定义请求头添加 headers?.forEach { key, value in urlRequest.setValue(value, forHTTPHeaderField: key) } // 添加默认User-Agent(很多服务器会验证这个) if urlRequest.value(forHTTPHeaderField: "User-Agent") == nil { urlRequest.setValue("CustomAlamofire/1.0", forHTTPHeaderField: "User-Agent") } self.request = urlRequest self.method = method self.parameters = parameters self.headers = headers }
2. 忽略了HTTP状态码的错误
URLSession的error只代表网络层面的错误(比如连接失败、超时),如果服务器返回4xx/5xx的状态码(比如400参数错误、401未授权),但响应体为空,error依然是nil,但data是空的。
你可以在responseData的闭包里添加状态码检查:
Alamofire.session.dataTask(with: request) { (data, response, error) in let result: Result if let error = error { result = Result.failure(error) completionHandler((data, response, error, request, result)) return } // 检查HTTP状态码 if let httpResponse = response as? HTTPURLResponse { print("服务器状态码:\(httpResponse.statusCode)") if !(200...299).contains(httpResponse.statusCode) { // 这里可以自定义一个HTTP错误 let httpError = NSError(domain: "HTTPError", code: httpResponse.statusCode, userInfo: [NSLocalizedDescriptionKey: "服务器返回错误状态码"]) result = Result.failure(httpError) completionHandler((data, response, httpError, request, result)) return } } completionHandler((data, response, error, request, Result.success)) }.resume()
3. 请求头缺失关键信息
有些服务器会验证请求头(比如User-Agent、Accept),如果你的自定义请求没有设置这些头,服务器可能返回空数据。而Playground里的URLSession会自动添加默认的请求头,所以能正常响应。
在上面的初始化代码里,我已经添加了默认的User-Agent,你也可以根据服务器要求添加Accept: application/json等头。
4. URLSession配置的差异
你的简易Alamofire用的是URLSessionConfiguration.default,这个配置会使用系统缓存、Cookie池。如果之前有错误的缓存响应,可能会返回空数据。可以尝试改用ephemeral配置(无缓存、无Cookie)测试:
fileprivate static let session = URLSession(configuration: URLSessionConfiguration.ephemeral)
内容的提问来源于stack exchange,提问作者kalafun

