Spec-Zone.ru › Flask 3.0

Контекст запроса

Контекст запроса отслеживает данные уровня запроса во время обработки запроса. Вместо того, чтобы передавать объект запроса каждой функции, выполняемой во время запроса, вместо этого используются прокси request и session.

Это аналогично Контексту приложения, который отслеживает данные уровня приложения независимо от запроса. Соответствующий контекст приложения подталкивается при подталкивании контекста запроса.

Назначение контекста

Когда приложение Flask обрабатывает запрос, оно создаёт объект Request на основе окружения, полученного от сервера WSGI. Поскольку рабочий процесс (поток, процесс или сопрограмма, в зависимости от сервера) обрабатывает только один запрос за раз, данные запроса можно считать глобальными для данного рабочего процесса в течение этого запроса. Flask использует термин локальные переменные контекста для этого.

Flask автоматически подталкивает контекст запроса при обработке запроса. Функции представления, обработчики ошибок и другие функции, выполняющиеся во время запроса, будут иметь доступ к прокси request, который указывает на объект запроса для текущего запроса.

Жизненный цикл контекста

Когда приложение Flask начинает обработку запроса, оно подталкивает контекст запроса, который также подталкивает контекст приложения. Когда запрос заканчивается, оно извлекает контекст запроса, а затем и контекст приложения.

Контекст уникален для каждого потока (или другого типа рабочего процесса). request не может быть передан другому потоку; другой поток имеет другое пространство контекста и не будет знать о запросе, на который указывает родительский поток.

Локальные переменные контекста реализованы с использованием contextvars Python и LocalProxy Werkzeug. Python автоматически управляет жизненным циклом переменных контекста, а прокси локальных переменных оборачивает этот интерфейс низкого уровня, чтобы сделать работу с данными проще.

Ручная подталкивания контекста

Если вы попытаетесь получить доступ к request или к чему-либо, что использует его, за пределами контекста запроса, вы получите это сообщение об ошибке:

RuntimeError: Working outside of request context.

This typically means that you attempted to use functionality that
needed an active HTTP request. Consult the documentation on testing
for information about how to avoid this problem.

Это обычно происходит только при тестировании кода, который ожидает активный запрос. Один из вариантов — использовать test client для имитации полного запроса. Или вы можете использовать test_request_context() в блоке with, и все, что выполняется в этом блоке, получит доступ к request, заполненному вашими тестовыми данными.

def generate_report(year):
    format = request.args.get("format")
    ...

with app.test_request_context(
    "/make_report/2017", query_string={"format": "short"}
):
    generate_report()

Если вы видите эту ошибку где-то ещё в своём коде, не связанном с тестированием, это, скорее всего, означает, что вам нужно переместить этот код в функцию представления.

Дополнительную информацию о том, как использовать контекст запроса из интерактивной оболочки Python, см. в разделе Работа с оболочкой.

Как работает контекст

Метод Flask.wsgi_app() вызывается для обработки каждого запроса. Он управляет контекстами во время обработки запроса. Внутренне, контексты запроса и приложения работают как стеки. Когда контексты подталкиваются, прокси, зависящие от них, становятся доступными и указывают на информацию из верхнего элемента.

При запуске запроса создаётся и подталкивается RequestContext, который сначала создаёт и подталкивает AppContext, если контекст для данного приложения ещё не является верхним контекстом. Пока эти контексты подталкиваются, прокси current_app, g, request и session доступны для исходного потока, обрабатывающего запрос.

Для изменения прокси во время запроса могут быть подталкиваемы другие контексты. Хотя это не распространённый шаблон, он может использоваться в сложных приложениях, например, для внутренних перенаправлений или объединения разных приложений.

После обработки запроса и создания и отправки ответа контекст запроса извлекается, что приводит к извлечению контекста приложения. Непосредственно перед извлечением, вызываются функции teardown_request() и teardown_appcontext(). Эти функции вызываются даже если во время обработки произошла необработанная ошибка.

Обработчики событий и ошибки

Flask обрабатывает запрос в несколько этапов, что может повлиять на запрос, ответ и то, как обрабатываются ошибки. Контексты активны на всех этих этапах.

Blueprint может добавлять обработчики для этих событий, специфичные для данного модуля. Обработчики модуля будут выполнены, если модуль владеет маршрутом, соответствующим запросу.

  1. Перед каждым запросом вызываются функции before_request(). Если одна из этих функций возвращает значение, другие функции пропускаются. Возвращаемое значение обрабатывается как ответ, и функция представления не вызывается.
  2. Если функции before_request() не вернули ответ, вызывается функция представления для соответствующего маршрута и возвращается ответ.
  3. Возвращаемое значение представления преобразуется в фактический объект ответа и передаётся функциям after_request(). Каждая функция возвращает изменённый или новый объект ответа.
  4. После возвращения ответа контексты извлекаются, вызывая функции teardown_request() и teardown_appcontext(). Эти функции вызываются даже если в какой-либо момент выше была поднята необработанная ошибка.

Если исключение возникает до выполнения функций разборки, Flask пытается сопоставить его с функцией errorhandler() для обработки исключения и возврата ответа. Если обработчик ошибок не найден или сам обработчик порождает исключение, Flask возвращает универсальный ответ 500 Internal Server Error. Функции разборки всё равно вызываются и получают объект исключения.

Если режим отладки включён, необработанные исключения не преобразуются в ответ 500, а вместо этого передаются серверу WSGI. Это позволяет серверу разработки представить интерактивный отладчик с трассировкой стека.

Обработчики разборки

Обработчики разборки независимы от обработки запроса и вместо этого вызываются контекстами при извлечении. Функции вызываются даже при наличии необработанного исключения во время обработки, а также для вручную подталкиваемых контекстов. Это означает, что нет гарантии, что другие части обработки запроса будут выполнены раньше. Убедитесь, что эти функции написаны таким образом, что не зависят от других обработчиков и не могут выйти из строя.

Во время тестирования может быть полезно отложить извлечение контекстов после завершения запроса, чтобы к их данным можно было получить доступ в тестовой функции. Используйте test_client() в качестве блока with, чтобы сохранить контексты до выхода из блока with.

from flask import Flask, request

app = Flask(__name__)

@app.route('/')
def hello():
    print('during view')
    return 'Hello, World!'

@app.teardown_request
def show_teardown(exception):
    print('after with block')

with app.test_request_context():
    print('during with block')

# teardown functions are called after the context with block exits

with app.test_client() as client:
    client.get('/')
    # the contexts are not popped even though the request ended
    print(request.path)

# the contexts are popped and teardown functions are called after
# the client with block exits

Сигналы

Отправляются следующие сигналы:

  1. request_started отправляется перед вызовом функций before_request().
  2. request_finished отправляется после вызова функций after_request().
  3. got_request_exception отправляется, когда обработка исключения начинается, но перед попыткой найти или вызвать errorhandler().
  4. request_tearing_down отправляется после вызова функций teardown_request().

Примечания по прокси

Некоторые объекты, предоставляемые Flask, являются прокси к другим объектам. К прокси обращаются одинаково для каждого потока рабочей нити, но они указывают на уникальный объект, привязанный к каждой рабочей нити за кулисами, как описано на этой странице.

Большую часть времени вам не нужно об этом беспокоиться, но есть некоторые исключения, когда полезно знать, что этот объект на самом деле является прокси:

  • Объекты-прокси не могут подделать свой тип как фактические типы объектов. Если вы хотите выполнить проверки экземпляра, вы должны сделать это на объекте, который проксируется.
  • Ссылка на проксируемый объект необходима в некоторых ситуациях, например, при отправке Сигналов или передаче данных в фоновый поток.

Если вам нужно получить доступ к базовому объекту, который проксируется, используйте метод _get_current_object():

app = current_app._get_current_object()
my_signal.send(app)

© 2010 Pallets
Licensed under the BSD 3-clause License.
https://flask.palletsprojects.com/en/3.0.x/reqcontext/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API