Python3 ThreadingHTTPServer 无法发送分块编码响应

问题描述 投票:0回答:2

我正在 Python3 中实现一个简单的反向代理,我需要使用

transfer-encoding chunked
模式发送响应。

我从这篇post中得到了提示,但在以here

描述的格式发送块时遇到了一些问题

如果我发送 length <= 9 bytes 的块,消息会被客户端正确接收,否则当发送 length >= 10 字节 的块时,似乎其中一些没有被接收,消息仍然卡在客户端等待中无限期

这是一个非工作代码的示例:

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”块

postman error

但是如果我改用这个长度:

    # 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个块都被正确解释) postman ok

部分版本信息:

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

预先感谢您的任何提示!

python http httpserver chunked-encoding chunked
2个回答
1
投票

我发布了解决方案(感谢 bugs.python.org 的 Martin Panter),以防其他人将来遇到同样的问题。

该行为是由块大小部分引起的,必须采用十六进制格式, 不是十进制

不幸的是,Mozilla docs 未指定格式,示例仅使用长度< 10. A formal definition is found 此处

总之,工作版本如下(使用

{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'))

0
投票

由于现代 Python 有 Unicode 字符串 需要注意的是,chunked的定义是:

chunk-size 字段是一串十六进制数字 指示块数据的大小(以八位字节为单位)。

所以很可能需要进行UTF-8编码 在计算长度之前而不是之后。

© www.soinside.com 2019 - 2024. All rights reserved.