串流內容

有時候您會想要傳送大量的資料給客戶端,遠遠超出您想要保存在記憶體中的資料量。當您在動態產生資料時,如何在不經過往返檔案系統的情況下將資料傳回給客戶端呢?

答案是使用生成器和直接回應。

基本用法

這是一個基本視圖函式,可以動態產生大量的 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()