尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Flask 如何用生成器和 stream_template 流式返回大数据响应

Flask 如何用生成器和 stream_template 流式返回大数据响应 Flask 如何用生成器和 stream_template 流式返回大数据响应【免费下载链接】flaskThe Python micro framework for building web applications.项目地址: https://gitcode.com/gh_mirrors/fl/flask当一个视图需要向客户端发送大量数据时比如一份需要现场生成的 CSV 文件或一个持续输出的时间线页面如果先把完整结果攒在内存或落盘再返回代价很大。Flask 的解决方案是用生成器generator直接返回和stream_template模板流式渲染数据一边生成一边发给客户端不必往返文件系统。本文依据官方文档 Streaming Contents 及相关源码给出这两条路径的完整写法和对应的硬约束。版本前提来自源码标注视图直接返回生成器会被转换为流式响应自 Flask 2.2 起支持见 src/flask/app.py 中versionchanged:: 2.2标注stream_template/stream_template_string自 Flask 2.2 起提供stream_with_context自 Flask 0.9 起提供见 src/flask/helpers.py 的versionadded标注。写流式视图前先明确响应头的硬约束这是流式响应与普通响应最大的差异官方文档将其单独列为HTTP Response Behavior一节HTTP 响应必须先发全部 header再发 bodybody 开始之后不能再发任何 header。因此所有 header 必须在响应开始之前、在生成器之外设置好。如果生成器会访问session务必在视图函数里也访问一次session这样Vary: cookieheader 才会被设置不要在生成器里修改session因为Set-Cookieheader 在 body 开始前就已发送修改不会生效。stream_with_context的源码 docstring 中也重复了这个警告并额外提醒通常更安全的做法是把需要的数据作为参数传给生成器而不是依赖上下文对象。路径一视图直接返回生成器Flask 对视图返回值的转换规则中有一条quickstart如果返回值是返回字符串或 bytes 的迭代器或生成器它会被当作流式响应处理。因此不需要手动构造Response直接返回生成器即可。官方文档给出的示例是一份现场生成的大型 CSVapp.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}其中iter_all_rows()是文档中的占位数据源替换成你自己逐行产出数据的函数即可每yield一行 CSV。返回值用(body, headers)元组附加Content-Type: text/csv——这正是上面header 必须在生成器外设置好约束的体现。文档说明每个yield表达式会直接发给浏览器。路径二用 stream_template 按块流式渲染模板Jinja 模板引擎支持逐块渲染模板、返回字符串迭代器。Flask 为此提供了stream_template和stream_template_string两个函数docs/api.rst 的 Template Rendering 一节实现在 src/flask/templating.pyfrom flask import stream_template app.get(/timeline) def timeline(): return stream_template(timeline.html)stream_template(template_name_or_list, **context)的说明按名称渲染模板并以流的形式返回字符串迭代器可直接作为视图的流式响应传入列表时渲染第一个实际存在的模板名。stream_template_string(source, **context)则从给定的源码字符串渲染。文档提示一个可预期的行为渲染流yield出来的片段大致对应模板中的语句块statement blocks而不是逐字符输出——排查为什么一段输出是一整块到达时对照这一点即可。生成器里要读 request 数据用 stream_with_context生成器运行时应用已经把控制权交还给 WSGI 服务器request代理在那时不会处于激活状态——如果在生成器里访问request会得到RuntimeError。如果生成器逻辑依赖request里的数据用stream_with_context包裹它请求上下文会在生成器运行期间保持激活src/flask/helpers.py 中的 docstring 说明它会保持request、session、g可用from flask import stream_with_context, request from markupsafe import escape app.route(/stream) def streamed_response(): def generate(): yield pHello yield escape(request.args[name]) yield !/p return stream_with_context(generate())它也可以作为装饰器使用app.get(/stream) def streamed_response(): stream_with_context def generate(): yield Hello yield request.args[name] yield ! return generate()最后一条规则可以减少对stream_with_context的依赖stream_template和stream_template_string在有请求激活时会自动使用stream_with_context所以模板流式渲染场景里通常不需要手动包裹。行为核对与已知限制文档没有提供专门的流式检查命令可依据文档明确描述的以下现象核对实现是否正确流是否真的在发生文档说明每个yield表达式会直接发给浏览器。以 CSV 示例为例请求/large.csv时浏览器收到的应是以text/csv类型、逐行到达的数据而不是等全部生成完毕的一次性响应。生成器里访问request报RuntimeError这是文档明确给出的现象根因是生成器运行时请求上下文已结束修复方式是用stream_with_context包裹或把所需数据作为参数传进生成器文档标注为更安全的做法。某些 WSGI 中间件会破坏流式行为文档特别提醒在 debug 环境中注意 profiler 等启用的中间件——如果流式响应在你的环境里退化成一次性返回先检查这一层。流式开始后的头修改不生效body 已开始时追加的 header包括对session的修改所依赖的Set-Cookie都会被忽略这是协议层面无法绕开的限制只能按第一节的约束在生成器外处理。【免费下载链接】flaskThe Python micro framework for building web applications.项目地址: https://gitcode.com/gh_mirrors/fl/flask创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表