Streaming内容

有时,您希望向客户机发送大量的数据,这比您希望在内存中保存的数据要多得多。但是,当您在运行中生成数据时,如何在没有文件系统往返的情况下将数据发送回客户机?

答案是使用生成器和直接响应。

基本用法

这是一个基本的视图函数,可以动态生成大量的csv数据。诀窍是拥有一个内部函数,该函数使用生成器生成数据,然后调用该函数并将其传递给响应对象:

@app.route('/large.csv')
def generate_large_csv():
    def generate():
        for row in iter_all_rows():
            yield f"{','.join(row)}\n"
    return app.response_class(generate(), mimetype='text/csv')

yield 表达式直接发送到浏览器。请注意,虽然一些WSGi中间软件可能会中断流,但是在使用配置文件和其他您可能启用的东西的调试环境中要小心。

从模板流式传输

Jinja2模板引擎还支持逐块呈现模板。Flask不会直接暴露此功能,因为它非常罕见,但您可以自己轻松做到:

def stream_template(template_name, **context):
    app.update_template_context(context)
    t = app.jinja_env.get_template(template_name)
    rv = t.stream(context)
    rv.enable_buffering(5)
    return rv

@app.route('/my-large-page.html')
def render_large_template():
    rows = iter_all_rows()
    return app.response_class(stream_template('the_template.html', rows=rows))

这里的技巧是从应用程序的jinja2环境中获取模板对象并调用 stream() 而不是 render() 它返回流对象而不是字符串。由于我们绕过了flask模板呈现函数并使用模板对象本身,因此我们必须确保通过调用 update_template_context() . 然后在迭代流时计算模板。因为每次执行yield操作时,服务器都会将内容刷新到客户机,您可能希望在模板中缓冲一些可以使用的项。 rv.enable_buffering(size) . 5 是理智的默认。

与上下文流式处理

Changelog

0.9 新版功能.

注意,当您传输数据时,请求上下文在函数执行时就已经不存在了。flask 0.9为您提供了一个助手,可以在执行生成器期间保持请求上下文:

from flask import stream_with_context, request

@app.route('/stream')
def streamed_response():
    def generate():
        yield 'Hello '
        yield request.args['name']
        yield '!'
    return app.response_class(stream_with_context(generate()))

如果没有:func:~flask.stream_with_context`函数,那么你将得到一个:class:`RuntimeError