Spec-Zone.ru › Flask 1.0

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

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

Сигналы

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

  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.0.x/reqcontext/

Spec-Zone.ru

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