Структура и жизненный цикл приложения

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

Настройка приложения

Первым шагом в создании приложения Flask является создание объекта приложения. Каждое приложение Flask является экземпляром класса Flask, в котором собраны все конфигурации, расширения и представления.

from flask import Flask

app = Flask(__name__)
app.config.from_mapping(
    SECRET_KEY="dev",
)
app.config.from_prefixed_env()

@app.route("/")
def index():
    return "Hello, World!"

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

Вся настройка приложения должна быть завершена до того, как вы начнете обслуживать свое приложение и обрабатывать запросы. Это связано с тем, что серверы WSGI распределяют работу между несколькими рабочими или могут быть распределены по нескольким машинам. Если конфигурация изменилась в одном рабочем, Flask не сможет обеспечить согласованность между другими рабочими.

Flask пытается помочь разработчикам отловить некоторые из этих проблем с упорядочиванием настроек, показывая ошибку, если методы, связанные с настройкой, вызываются после обработки запросов. В этом случае вы увидите эту ошибку:

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

Однако Flask не в состоянии обнаружить все случаи неправильной установки. В общем, не делайте ничего для изменения объекта Flask app и объектов Blueprint внутри функций представления, которые выполняются во время запросов. Это включает в себя:

  • Добавление маршрутов, функций представления и других обработчиков запросов с помощью @app.route, @app.errorhandler, @app.before_request и т.д.

  • Регистрация чертежей.

  • Загрузка конфигурации с помощью app.config.

  • Настройка окружения шаблона Jinja с помощью app.jinja_env.

  • Установка интерфейса сессии вместо cookie по умолчанию itsdangerous.

  • Установка поставщика JSON с помощью app.json, вместо поставщика по умолчанию.

  • Создание и инициализация расширений Flask.

Обслуживание приложения

Flask - это фреймворк приложений WSGI. Вторая половина WSGI - это сервер WSGI. Во время разработки Flask через Werkzeug предоставляет WSGI-сервер для разработки с помощью команды CLI flask run. Когда вы закончите разработку, используйте рабочий сервер для обслуживания вашего приложения, см. раздел Развертывание в производство.

Независимо от того, какой сервер вы используете, он будет следовать спецификации WSGI PEP 3333. Серверу WSGI будет указано, как получить доступ к объекту вашего приложения Flask, который является приложением WSGI. Затем он начнет слушать HTTP-запросы, переведет данные запроса в среду WSGI и вызовет приложение WSGI с этими данными. Приложение WSGI вернет данные, преобразованные в ответ HTTP.

  1. Браузер или другой клиент делает HTTP-запрос.

  2. Сервер WSGI получает запрос.

  3. Сервер WSGI преобразует данные HTTP в дикту WSGI environ.

  4. Сервер WSGI вызывает приложение WSGI с помощью environ.

  5. Flask, приложение WSGI, выполняет всю свою внутреннюю обработку для маршрутизации запроса к функции представления, обработки ошибок и т.д.

  6. Flask переводит возврат функции View в данные ответа WSGI и передает их серверу WSGI.

  7. Сервер WSGI создает и отправляет HTTP-ответ.

  8. Клиент получает ответ HTTP.

Middleware

Приведенное выше приложение WSGI - это вызываемый объект, который ведет себя определенным образом. Middleware - это приложение WSGI, которое оборачивает другое приложение WSGI. Эта концепция схожа с декораторами Python. Внешнее промежуточное ПО будет вызываться сервером. Оно может изменять переданные ему данные, затем вызывать WSGI-приложение (или другое промежуточное ПО), которое оно обертывает, и так далее. И оно может принимать возвращаемое значение этого вызова и изменять его дальше.

С точки зрения сервера WSGI, существует одно приложение WSGI - то, которое он вызывает напрямую. Как правило, Flask является «настоящим» приложением в конце цепочки промежуточного ПО. Но даже Flask может вызывать другие приложения WSGI, хотя это продвинутый и редкий случай использования.

Чаще всего в Flask используется промежуточное ПО Werkzeug ProxyFix, которое изменяет запрос так, чтобы он выглядел так, как будто он пришел непосредственно от клиента, даже если по пути он прошел через HTTP-прокси. Существуют и другие промежуточные программы, которые могут обслуживать статические файлы, аутентификацию и т.д.

Как обрабатывается запрос

Для нас интересна та часть описанных выше действий, когда Flask вызывается сервером WSGI (или промежуточным ПО). В этот момент он будет делать довольно много для обработки запроса и генерации ответа. В самом простом случае он сопоставит URL с функцией представления, вызовет функцию представления и передаст возвращаемое значение обратно на сервер. Но есть много других частей, которые вы можете использовать для настройки его поведения.

  1. Сервер WSGI вызывает объект Flask, который вызывает Flask.wsgi_app().

  2. Создается объект RequestContext. Он преобразует дикт WSGI environ в объект Request. Также создается объект AppContext.

  3. Нажимается app context, что делает доступными current_app и g.

  4. Посылается сигнал appcontext_pushed.

  5. Нажимается request context, что делает доступными request и session.

  6. Открывается сессия, загружая все существующие данные сессии с помощью session_interface приложения, экземпляра SessionInterface.

  7. URL сопоставляется с правилами URL, зарегистрированными в декораторе route() во время настройки приложения. Если совпадения нет, ошибка - обычно 404, 405 или перенаправление - сохраняется для последующей обработки.

  8. Посылается сигнал request_started.

  9. Вызываются любые декорированные функции url_value_preprocessor().

  10. Вызываются любые декорированные функции before_request(). Если любая из этих функций возвращает значение, оно сразу же рассматривается как ответ.

  11. Если несколько шагов назад URL-адрес не соответствовал маршруту, эта ошибка возникает сейчас.

  12. Вызывается функция представления с декором route(), связанная с найденным URL, и возвращает значение, которое будет использоваться в качестве ответа.

  13. Если на каком-либо этапе возникло исключение, и существует декорированная функция errorhandler(), соответствующая классу исключения или коду ошибки HTTP, она вызывается для обработки ошибки и возврата ответа.

  14. Что бы ни вернуло значение ответа - функция до запроса, представление или обработчик ошибок, это значение преобразуется в объект Response.

  15. Вызываются любые декорированные функции after_this_request(), а затем очищаются.

  16. Вызываются любые after_request() декорированные функции, которые могут модифицировать объект ответа.

  17. Сессия сохраняется, сохраняя все измененные данные сессии с помощью session_interface приложения.

  18. Посылается сигнал request_finished.

  19. Если на каком-либо шаге возникло исключение, и оно не было обработано функцией обработчика ошибок, оно будет обработано сейчас. Исключения HTTP рассматриваются как ответы с соответствующим кодом статуса, другие исключения преобразуются в общий ответ 500. Посылается сигнал got_request_exception.

  20. Статус, заголовки и тело объекта ответа возвращаются на сервер WSGI.

  21. Вызываются любые декорированные функции teardown_request().

  22. Посылается сигнал request_tearing_down.

  23. Контекст запроса выскочил, request и session больше не доступны.

  24. Вызываются любые декорированные функции teardown_appcontext().

  25. Посылается сигнал appcontext_tearing_down.

  26. Контекст приложения раскрыт, current_app и g больше не доступны.

  27. Посылается сигнал appcontext_popped.

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

Вернуться на верх