在Python 3.3+(或任何其他内置的python HTTP客户端库)中使用http.client
,我如何一次只读取一个HTTP块的分块HTTP响应?
我正在扩展现有的测试夹具(使用http.client
用python编写),用于使用HTTP的分块传输编码写入其响应的服务器。为简单起见,假设我希望能够在客户端收到HTTP块时打印消息。
我的代码遵循一个相当标准的模式来读取大量响应:
conn = http.client.HTTPConnection(...)
conn.request(...)
response = conn.getresponse()
resbody = []
while True:
chunk = response.read(1024)
if len(chunk):
resbody.append(chunk)
else:
break
conn.close();
但无论服务器是发送10字节块还是10MiB块,都会读取1024字节块。
我正在寻找的内容如下:
while True:
chunk = response.readchunk()
if len(chunk):
resbody.append(chunk)
else
break
如果使用http.client
无法做到这一点,是否可以使用其他内置的http客户端库?如果使用内置客户端lib无法实现,是否可以使用pip
可安装模块?
答案 0 :(得分:5)
更新
分块传输编码的好处是允许传输动态生成的内容。 HTTP库是否允许您读取单个块是一个单独的问题(请参阅RFC 2616 - Section 3.6.1)。
我可以看到你想要做的事情会有用,但标准的python http客户端库没有你想要的东西而没有一些hackery(参见http.client和httplib)。 / p>
您尝试做的事情可能适用于您的测试夹具,但在野外没有任何保证。客户端读取的数据的分块可能与服务器发送的数据的分块不同。例如。在代理服务器到达之前,数据可能已被“重新分块”(请参阅RFC 2616 - Section 3.2 - Framing Techniques)。
诀窍是告诉响应对象它没有分块(resp.chunked = False
),以便它返回原始字节。这允许您在返回时解析每个块的大小和数据。
import http.client
conn = http.client.HTTPConnection("localhost")
conn.request('GET', "/")
resp = conn.getresponse()
resp.chunked = False
def get_chunk_size():
size_str = resp.read(2)
while size_str[-2:] != b"\r\n":
size_str += resp.read(1)
return int(size_str[:-2], 16)
def get_chunk_data(chunk_size):
data = resp.read(chunk_size)
resp.read(2)
return data
respbody = ""
while True:
chunk_size = get_chunk_size()
if (chunk_size == 0):
break
else:
chunk_data = get_chunk_data(chunk_size)
print("Chunk Received: " + chunk_data.decode())
respbody += chunk_data.decode()
conn.close()
print(respbody)
答案 1 :(得分:1)
我发现像这样使用请求库更容易
r = requests.post(url, data=payload, headers=headers, stream=True)
for line in (r.raw.read_chunked()):
print(line)