带认证HTTP代理下,如何用NWConnection识别响应编码并分离头体
解决方案
1. 拆分HTTP响应头与响应体
HTTP协议规定,响应头和响应体通过**\r\n\r\n**(两个连续回车换行)分隔。拆分步骤如下:
- 将收到的完整
Data转为ASCII字符串(HTTP头仅使用ASCII编码,避免UTF-8转码异常) - 定位
\r\n\r\n的位置,以此为界拆分出头部数据和体部数据 - 若找不到分隔符,判定为无效响应
2. 提取编码类型
响应的压缩编码格式存在于响应头的Content-Encoding字段中,解析该字段值后即可传入解码函数。
修改后的响应处理逻辑
在readAllData的回调中替换原解码逻辑,添加拆分和编码提取步骤:
// 在readAllData的completion中替换原有解码代码 guard let data = finalData else { print("No data received or unable to read data.") completion(false) return } // 1. 拆分响应头与响应体 let separator = "\r\n\r\n".data(using: .ascii)! guard let separatorIndex = data.range(of: separator)?.upperBound else { print("Invalid HTTP response: no header-body separator found") completion(false) return } let headerData = data[..<separatorIndex] let bodyData = data[separatorIndex...] // 2. 解析响应头,提取Content-Encoding guard let headerString = String(data: headerData, encoding: .ascii) else { print("Failed to parse response header") completion(false) return } var contentEncoding: String? for line in headerString.components(separatedBy: "\r\n") { let trimmedLine = line.trimmingCharacters(in: .whitespaces) guard trimmedLine.lowercased().starts(with: "content-encoding:") else { continue } let parts = trimmedLine.components(separatedBy: ":") if parts.count >= 2 { contentEncoding = parts[1].trimmingCharacters(in: .whitespaces) break } } // 3. 使用提取的编码类型解码响应体 if let body = decodeRequest(data: bodyData, encodingType: contentEncoding) { completion(true) } else { print("Unable to decode response body.") completion(false) }
优化后的解码函数(简化冗余逻辑)
import Foundation import Gzip import SwiftyDeflate import SwiftBrotli func decodeRequest(data: Data, encodingType: String?) -> String? { let encoding = encodingType?.lowercased() ?? "" switch encoding { case "gzip": return try? data.gunzipped().flatMap { String(data: $0, encoding: .utf8) } ?? "" case "deflate": return try? data.deflateDecompress().flatMap { String(data: $0, encoding: .utf8) } ?? "" case "br", "brotli": return Brotli().decompress(data).successValue.flatMap { String(data: $0, encoding: .utf8) } ?? "" default: return String(data: data, encoding: .utf8) ?? "" } }
补充说明
- 若
Content-Encoding字段不存在,说明响应未被压缩,解码函数会直接返回原始文本 - 部分服务器可能返回多个编码值(如
gzip, deflate),可根据需求优先处理第一个值,或扩展解码函数支持链式解码 - HTTP头转字符串使用
.ascii编码更可靠,符合HTTP标准对头部字符的规定
内容的提问来源于stack exchange,提问作者Ahmed Zaidan
相关产品推荐
相关产品推荐

