转发 gzip 字节并配上描述它们的标头
在基于 Requests 的代理中选择编码或解码后的负载,然后让下游响应带上匹配的 content 标头和它自己的分帧。
如果 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 错误:本示例选择抛出错误,而不是转发它们。