Python3 ThreadingHTTPServer 无法发送分块编码响应
Python3 ThreadingHTTPServer fails to send chunked encoded response
我正在 Python3 中实现一个简单的反向代理,我需要使用 transfer-encoding chunked
模式发送响应。
我从这个 post but I have some problems when sending the chunks in the format described here
中得到了启发
如果我发送 length <= 9 bytes 的块,客户端会正确接收消息,否则发送 length >= 10 bytes 的块时,好像有些没收到,消息一直卡在客户端无限等待
这是一个非工作代码的例子:
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
class ProxyHTTPRequestHandler(BaseHTTPRequestHandler):
protocol_version = 'HTTP/1.1'
def do_GET(self, body=True):
# HTTP 200 + minimal HTTP headers in response
self.send_response(200)
self.send_header('transfer-encoding', 'chunked')
self.send_header('Content-Type', 'text/plain')
self.end_headers()
# writing 5 chunks of 10 characters
for i in range(5):
text = str(i+1) * 10 # concatenate 10 chars
chunk = '{0:d}\r\n'.format(len(text)) + text + '\r\n'
self.wfile.write(chunk.encode(encoding='utf-8'))
# writing close sequence
close_chunk = '0\r\n\r\n'
self.wfile.write(close_chunk.encode(encoding='utf-8'))
def main():
try:
server_address = ('127.0.0.1', 8099)
# I use ThreadingHTTPServer but the problem persists also with HTTPServer
httpd = ThreadingHTTPServer(server_address, ProxyHTTPRequestHandler)
print('http server is running')
httpd.serve_forever()
except KeyboardInterrupt:
print(" ^C entered, stopping web server...")
httpd.socket.close()
if __name__ == '__main__':
main()
在这种情况下,几秒钟后,只有当我手动停止 python 执行时,Postman 中的结果如下。请注意缺少的“2222222222”块
但是如果我改用这个长度:
# writing the same 5 chunks of 9 characters
for i in range(5):
text = str(i+1) * 9 # concatenate 9 chars
chunk = '{0:d}\r\n'.format(len(text)) + text + '\r\n'
self.wfile.write(chunk.encode(encoding='utf-8'))
# writing close sequence
close_chunk = '0\r\n\r\n'
self.wfile.write(close_chunk.encode(encoding='utf-8'))
通信正确结束(6ms 后所有 5 个块都被正确解释)
部分版本信息:
HTTP Client: Postman 8.10
(venv) manuel@MBP ReverseProxy % python -V
Python 3.9.2
(venv) manuel@MBP ReverseProxy % pip freeze
certifi==2021.10.8
charset-normalizer==2.0.6
idna==3.2
requests==2.26.0
urllib3==1.26.7
提前感谢您的任何提示!
我 post 解决方案(感谢来自 bugs.python.org 的 Martin Panter)以防其他人将来遇到同样的问题。
该行为是由块大小部分引起的,必须是十六进制格式,
不是十进制.
不幸的是来自 Mozilla docs the format was not specified and the example used only length < 10. A formal definition is found here
总之,工作版本如下(使用 {0:x}
而不是 {0:d}
)
# writing the same 5 chunks of 9 characters
for i in range(5):
text = str(i+1) * 9 # concatenate 9 chars
chunk = '{0:x}\r\n'.format(len(text)) + text + '\r\n'
self.wfile.write(chunk.encode(encoding='utf-8'))
# writing close sequence
close_chunk = '0\r\n\r\n'
self.wfile.write(close_chunk.encode(encoding='utf-8'))
我正在 Python3 中实现一个简单的反向代理,我需要使用 transfer-encoding chunked
模式发送响应。
我从这个 post but I have some problems when sending the chunks in the format described here
中得到了启发如果我发送 length <= 9 bytes 的块,客户端会正确接收消息,否则发送 length >= 10 bytes 的块时,好像有些没收到,消息一直卡在客户端无限等待
这是一个非工作代码的例子:
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
class ProxyHTTPRequestHandler(BaseHTTPRequestHandler):
protocol_version = 'HTTP/1.1'
def do_GET(self, body=True):
# HTTP 200 + minimal HTTP headers in response
self.send_response(200)
self.send_header('transfer-encoding', 'chunked')
self.send_header('Content-Type', 'text/plain')
self.end_headers()
# writing 5 chunks of 10 characters
for i in range(5):
text = str(i+1) * 10 # concatenate 10 chars
chunk = '{0:d}\r\n'.format(len(text)) + text + '\r\n'
self.wfile.write(chunk.encode(encoding='utf-8'))
# writing close sequence
close_chunk = '0\r\n\r\n'
self.wfile.write(close_chunk.encode(encoding='utf-8'))
def main():
try:
server_address = ('127.0.0.1', 8099)
# I use ThreadingHTTPServer but the problem persists also with HTTPServer
httpd = ThreadingHTTPServer(server_address, ProxyHTTPRequestHandler)
print('http server is running')
httpd.serve_forever()
except KeyboardInterrupt:
print(" ^C entered, stopping web server...")
httpd.socket.close()
if __name__ == '__main__':
main()
在这种情况下,几秒钟后,只有当我手动停止 python 执行时,Postman 中的结果如下。请注意缺少的“2222222222”块
但是如果我改用这个长度:
# writing the same 5 chunks of 9 characters
for i in range(5):
text = str(i+1) * 9 # concatenate 9 chars
chunk = '{0:d}\r\n'.format(len(text)) + text + '\r\n'
self.wfile.write(chunk.encode(encoding='utf-8'))
# writing close sequence
close_chunk = '0\r\n\r\n'
self.wfile.write(close_chunk.encode(encoding='utf-8'))
通信正确结束(6ms 后所有 5 个块都被正确解释)
部分版本信息:
HTTP Client: Postman 8.10
(venv) manuel@MBP ReverseProxy % python -V
Python 3.9.2
(venv) manuel@MBP ReverseProxy % pip freeze
certifi==2021.10.8
charset-normalizer==2.0.6
idna==3.2
requests==2.26.0
urllib3==1.26.7
提前感谢您的任何提示!
我 post 解决方案(感谢来自 bugs.python.org 的 Martin Panter)以防其他人将来遇到同样的问题。
该行为是由块大小部分引起的,必须是十六进制格式, 不是十进制.
不幸的是来自 Mozilla docs the format was not specified and the example used only length < 10. A formal definition is found here
总之,工作版本如下(使用 {0:x}
而不是 {0:d}
)
# writing the same 5 chunks of 9 characters
for i in range(5):
text = str(i+1) * 9 # concatenate 9 chars
chunk = '{0:x}\r\n'.format(len(text)) + text + '\r\n'
self.wfile.write(chunk.encode(encoding='utf-8'))
# writing close sequence
close_chunk = '0\r\n\r\n'
self.wfile.write(close_chunk.encode(encoding='utf-8'))