http.client调用时如何分块解压Gzip编码的响应数据
报错根因
- 你每次读取的20字节是完整gzip压缩流的截断片段,不是独立的合法gzip数据段。gzip本身有固定的文件头、校验尾、连续压缩块结构,单独把截断的小片段传给
gzip.decompress()会直接触发格式识别错误,也就是你看到的not a gzipped file报错。 - 代码存在逻辑错误:解压操作后你调用
json.loads(chunk)传入的是未解压的原始压缩块,就算解压步骤正常,这行也会抛出JSON解析错误。
实现方案
不需要手动拆分原始压缩块做解压,直接用标准库gzip.GzipFile包装响应流即可,它会内部维护解压缓冲区,自动处理跨块的gzip格式校验、拼接逻辑,全程边读边解压,不会把全量响应加载到内存,符合你的要求。
注意如果你的请求头里没有声明接收gzip编码,需要补上对应头,避免服务端返回未压缩内容导致解析失败。
import http.client import ssl import gzip import json connection = http.client.HTTPSConnection(api, context=ssl._create_unverified_context()) # 补全gzip编码声明 request_headers = auth.copy() if "Accept-Encoding" not in request_headers: request_headers["Accept-Encoding"] = "gzip" connection.request('GET', api_url, headers=request_headers) response = connection.getresponse() # 流式包装gzip流 with gzip.GzipFile(fileobj=response) as decompressed_stream: # 场景1:接口返回逐行分隔的JSON(NDJSON流、日志类流式接口),直接逐行解析,内存占用极低 for raw_line in decompressed_stream: raw_line = raw_line.strip() if not raw_line: continue parsed_data = json.loads(raw_line) print(parsed_data) # 场景2:如果是单个超大JSON对象,按固定大小读取解压后的内容 # 注意:单块内容是JSON片段,不能直接json.loads,需要自行拼接或搭配流式JSON解析器处理 # while chunk := decompressed_stream.read(64 * 1024): # 每次读取64KB解压后内容,可按需调整块大小 # # 自定义处理解压后的字节块 # print(len(chunk))
注意事项
- 禁止直接对原始响应的截断压缩块调用
gzip.decompress(),该方法仅支持传入完整的gzip压缩字节串,无法处理流片段。 - 如果返回的是单个完整大JSON,逐块读取得到的是不完整的JSON片段,直接调用
json.loads()会报错,需要根据接口返回的格式选择逐行解析、全量拼接或流式JSON解析方案。 - 整个流程全程流式读写,不会将全量压缩内容、解压内容一次性加载到内存,满足低内存占用的要求。
内容的提问来源于stack exchange,提问作者qwerty
相关产品推荐
相关产品推荐

