You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

带认证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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 05:53:19