【问题标题】:Flask and Transfer-Encoding: chunked烧瓶和传输编码:分块
【发布时间】:2026-01-18 10:25:02
【问题描述】:

我们正在尝试让 Flask 网络服务正常工作,但我们在流式传输帖子方面遇到了一些问题 - 即当标题包含 Transfer-Encoding: 分块时。

似乎默认烧瓶不支持 HTTP 1.1。有解决办法吗?

我们正在运行这个命令:

$ curl -v -X PUT  --header "Transfer-Encoding: chunked" -d @pylucene-3.6.1-2-src.tar.gz "http://localhost:5000/async-test"

针对此代码:

@app.route("/async-test", methods=['PUT'])
def result():
    print '------->'+str(request.headers)+'<------------'
    print '------->'+str(request.data)+'<------------'
    print '------->'+str(request.form)+'<------------'
    return 'OK'

这是 curl 输出:

$ curl -v -X PUT  --header "Transfer-Encoding: chunked" -d @pylucene-3.6.1-2-src.tar.gz "http://localhost:5000/async-test"
* About to connect() to localhost port 5000 (#0)
*   Trying ::1... Connection refused
*   Trying 127.0.0.1... connected
* Connected to localhost (127.0.0.1) port 5000 (#0)
> PUT /async-test HTTP/1.1
> User-Agent: curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5
> Host: localhost:5000
> Accept: */*
> Transfer-Encoding: chunked
> Content-Type: application/x-www-form-urlencoded
> Expect: 100-continue
>
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Content-Type: text/html; charset=utf-8
< Content-Length: 2
< Server: Werkzeug/0.8.3 Python/2.7.1
< Date: Wed, 02 Jan 2013 21:43:24 GMT
<

这是 Flask 服务器的输出:

* Running on 0.0.0.0:5000/ 
------->Transfer-Encoding: chunked
 Content-Length:
 User-Agent: curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5
 Host: localhost:5000
 Expect: 100-continue
 Accept: */*
 Content-Type: application/x-www-form-urlencoded

 <------------
 -------><------------
 ------->ImmutableMultiDict([])<------------

【问题讨论】:

  • 你找到解决办法了吗?
  • 我一定没有打开通知,所以直到现在我才看到这条评论。 Waqas 的回答是正确的;我们将测试代码移至 Java。

标签: python http flask


【解决方案1】:

它不是 Flask Python,它是 mod_wsgi。只有 mod_wsgi 3.0+ 版本开始支持分块 http 传输。 Flask Python 在内部使用 Werkzeug 工具包作为 mod_wsgi 的接口。如果您从 apt 源安装它,它可能是旧版本。

尝试编译最新版本的mod_wsgi,然后安装Flask框架,或许可以解决问题。

【讨论】:

    【解决方案2】:

    这对我有用,但它不是最优雅的填充分块解析的方式。我使用了将身体贴在响应环境中的方法。

    Get raw POST body in Python Flask regardless of Content-Type header

    但添加了处理分块解析的代码

    class WSGICopyBody(object):
        def __init__(self, application):
            self.application = application
    
        def __call__(self, environ, start_response):
            from cStringIO import StringIO
            input = environ.get('wsgi.input')
            length = environ.get('CONTENT_LENGTH', '0')
            length = 0 if length == '' else int(length)
            body = ''
            if length == 0:
                environ['body_copy'] = ''
                if input is None:
                    return
                if environ.get('HTTP_TRANSFER_ENCODING','0') == 'chunked':
                    size = int(input.readline(),16)
                    while size > 0:
                        body += input.read(size+2)
                        size = int(input.readline(),16)
            else:
                body = environ['wsgi.input'].read(length)
            environ['body_copy'] = body
            environ['wsgi.input'] = StringIO(body)
    
            # Call the wrapped application
            app_iter = self.application(environ, 
                                        self._sr_callback(start_response))
    
            # Return modified response
            return app_iter
    
        def _sr_callback(self, start_response):
            def callback(status, headers, exc_info=None):
    
                # Call upstream start_response
                start_response(status, headers, exc_info)
            return callback
    
    
    app.wsgi_app = WSGICopyBody(app.wsgi_app)
    

    用它来解决它

    request.environ['body_copy']
    

    【讨论】: