流式内容¶
有时,您希望向客户端发送大量数据,远超您希望保存在内存中的数据。但是,当您实时生成数据时,如何在不往文件系统进行往返的情况下将数据发送回客户端?
答案是使用生成器和直接响应。
基本用法¶
这是一个基本视图函数,它实时生成大量 CSV 数据。诀窍在于有一个使用生成器生成数据的内部函数,然后调用该函数并将其传递给响应对象
@app.route('/large.csv')
def generate_large_csv():
def generate():
for row in iter_all_rows():
yield f"{','.join(row)}\n"
return generate(), {"Content-Type": "text/csv"}
每个 yield
表达式都会直接发送到浏览器。但请注意,某些 WSGI 中间件可能会中断流式处理,因此请在调试环境中小心使用分析器和其他可能已启用的内容。
从模板进行流式处理¶
Jinja2 模板引擎支持逐个部分渲染模板,返回字符串迭代器。Flask 提供了 stream_template()
和 stream_template_string()
函数,以便更轻松地使用此功能。
from flask import stream_template
@app.get("/timeline")
def timeline():
return stream_template("timeline.html")
渲染流产生的部分往往与模板中的语句块相匹配。
使用上下文进行流式处理¶
在生成器运行时,request
不会处于活动状态,因为此时视图已返回。如果您尝试访问 request
,您将收到 RuntimeError
。
如果您的生成器函数依赖于 request
中的数据,请使用 stream_with_context()
包装器。这将在生成器期间保持请求上下文处于活动状态。
from flask import stream_with_context, request
from markupsafe import escape
@app.route('/stream')
def streamed_response():
def generate():
yield '<p>Hello '
yield escape(request.args['name'])
yield '!</p>'
return stream_with_context(generate())
它还可以用作装饰器。
@stream_with_context
def generate():
...
return generate()
如果请求处于活动状态,stream_template()
和 stream_template_string()
函数会自动使用 stream_with_context()
。