Потоковая передача контента
Иногда вам нужно отправить клиенту огромное количество данных, намного больше, чем вы хотите хранить в памяти. Но как вы отправляете эти данные клиенту на лету, минуя обращение к файловой системе?
Ответ — использование генераторов и прямых ответов.
Базовое использование
Это базовая функция представления, генерирующая большое количество данных 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(), если активен запрос.
© 2010 Pallets
Licensed under the BSD 3-clause License.
https://flask.palletsprojects.com/en/3.0.x/patterns/streaming/