Spec-Zone.ru › Flask 1.1

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

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

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

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

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

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

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

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

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

Локальные переменные контекста реализованы в Werkzeug. Подробнее о том, как это работает внутри, см. Локальные переменные контекста.

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

Если вы попытаетесь получить доступ к 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() используется для обработки каждого запроса. Он управляет контекстами во время запроса. Внутренне, контексты запроса и приложения работают как стеки, _request_ctx_stack и _app_ctx_stack. Когда контексты помещаются в стек, псевдонимы, зависящие от них, становятся доступными и указывают на информацию из верхнего контекста стека.

В начале запроса создается и подталкивается 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_ENV установлена в 'development'), ошибка и данные будут сохранены и отображены в интерактивном отладчике.

Это поведение можно контролировать с помощью конфигурации PRESERVE_CONTEXT_ON_EXCEPTION. Как описано выше, по умолчанию она установлена в True в среде разработки.

Не включайте PRESERVE_CONTEXT_ON_EXCEPTION в рабочей среде, так как это приведёт к утечке памяти в случае исключений.

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

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

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

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

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

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

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

Spec-Zone.ru

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