如何在Flask中获取裸wsgi流?

时间:2015-06-23 15:30:50

标签: python flask wsgi werkzeug

使用Flask,我想了解一下wsgi.input参考资料。看一下代码,似乎有不止一种方法可以做到这一点,两者都出现在:

werkzeug.wsgi.get_input_stream(environ, safe_fallback=True):
    ...
    if environ.get('wsgi.input_terminated'):
        return stream
    ...
    if content_length is None:
        return safe_fallback and _empty_stream or stream
    ...

令人讨厌的是,我无法弄清楚如何实际发生这些情况(并且他们在文档中几乎没有提及)。

wsgi.input_terminated:我知道我可以设置wsgi环境,如果我使用像Apache这样的合适服务器但我如何在Flask开发服务器下进行,因为Werkzeug在werkzeug中硬编码其wsgi环境。 serving.make_environ()?

safe_fallback:根本无法解决这个问题......如果这个参数只是自己调用并且从未通过,那么这个参数在这里做了什么?我应该如何激活它?

这里很容易遗漏一些东西......

3 个答案:

答案 0 :(得分:2)

我知道这是一个非常古老的线程,但我找到了一种方法来处理分块编码请求(我需要流而不是数据)和自定义python应用程序(gunicorn + flask),所以不要使用flask.Flask作为应用程序我创建了子类:

class FlaskApp(flask.Flask):
    def request_context(self, environ):
        # it's the only way I've found to handle chunked encoding request (otherwise flask.request.stream is empty)
        environ['wsgi.input_terminated'] = 1
        return super(FlaskApp, self).request_context(environ)

任何人都更好地了解如何以更好的方式做到这一点?

答案 1 :(得分:2)

这是@javabrett函数在他对@ddzialek的答案中的建议中稍微复杂一点的版本。这个在设置标志之前检查分块输入(我不是肯定的,但是设置你可能不需要的标志似乎不是一个好主意。)

@app.before_request
def handle_chunking():
    """
    Sets the "wsgi.input_terminated" environment flag, thus enabling
    Werkzeug to pass chunked requests as streams; this makes the API
    compliant with the HTTP/1.1 standard.  The gunicorn server should set
    the flag, but this feature has not been implemented.
    """

    transfer_encoding = request.headers.get("Transfer-Encoding", None)
    if transfer_encoding == "chunked":
        request.environ["wsgi.input_terminated"] = True

实际出现的“Transfer-Encoding”的值可能是Unicode而不是ASCII,因此“u'chunked”会更准确 - 但对于ASCII范围内的字符,差异无关紧要( Python将以任何方式匹配字符串),而Python 3不需要“u”。

编辑:重要的是要注意一些WSGI服务器不再需要此修复程序。但是,gunicorn确实如此(希望问题是fixed soon,但目前Flask代码需要上述修复。)

答案 2 :(得分:1)

@ddzialak发布的解决方案很有效,但是使用request.stream.read(chunk_size)或request.get_data()读取流会提供完整的流内容,包括标题。以下是我用来获取他们使用的信息的工具:

str_data    = request.get_data() # stream data
pattern = re.compile(r'\r\n\r\n(.+?)\n\r\n', flags=re.DOTALL) # content regex
file_data   = pattern.findall( str_data.decode('UTF-8') )[0] # what my tools use