Spec-Zone.ru › Flask 2.2

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

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

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

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

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

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

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

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

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

Локальные переменные контекста реализованы с использованием Python contextvars и Werkzeug LocalProxy. 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', data={'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

Сигналы

Если signals_available имеет значение true, отправляются следующие сигналы:

  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)

© 2007–2022 Pallets
Licensed under the BSD 3-clause License.
https://flask.palletsprojects.com/en/2.2.x/reqcontext/

Spec-Zone.ru

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