Flask和传输编码:分块

13

我们正在尝试让Flask Web服务工作,但我们在流式发布中遇到了一些问题 - 即当标题包括Transfer-Encoding: chunked时。

似乎默认的Flask不支持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。 - James Percent
2个回答

6

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

尝试编译最新版本的mod_wsgi,然后安装Flask框架,可能会解���问题。


2
这对我来说可行,但不是最优雅的分块解析垫片方法。我使用了将正文放入响应环境的方法。 无论Content-Type标头如何,获取Python Flask中的原始POST正文 但是添加了用于处理分块解析的代码。
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']

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接