如果 Requests 已经解压了正文,再用 Content-Encoding: gzip 转发,就等于要求下一个客户端再次解压。在复制标头之前,先决定代理发送哪种负载表示。

发送的负载content 标头
原始编码字节保留适用的编码和精确的负载长度
解码后的字节移除已解码的编码;移除或重新计算相应长度

对于编码后的负载字节,这段代码读取 urllib3 的原始流而不做 content 解码:

with requests.get(url, stream=True, timeout=(5, 30)) as upstream:
    upstream.raise_for_status()
    for block in upstream.raw.stream(65536, decode_content=False):
        downstream.write(block)

downstream 是现有的响应输出。它的状态和标头必须已经遵循所选策略;这段代码并不实现完整的代理服务器。

传输分帧与 gzip content 编码是两回事。上游 HTTP 库已经处理了分帧,包括去除分块,所以不要盲目复制 Transfer-Encoding。即使负载仍保持 gzip 编码,下游服务器也会为自己的响应分帧。

response.text 之后再按 UTF-8 编码也会改变表示形式,无法保留任意二进制数据。在每条路径上都要关闭或消费上游响应,并按代理约定处理 HTTP 错误:本示例选择抛出错误,而不是转发它们。

相关文章