应用程序结构和生命周期

FASK使编写Web应用程序变得非常容易。但是,应用程序及其处理的每个请求都有相当多的不同部分。了解应用程序设置、服务和处理请求过程中发生的情况将帮助您了解Flask中可能发生的事情以及如何构建应用程序。

应用程序设置

创建FlaskTM应用程序的第一步是创建应用程序对象。每个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服务器在多个工作进程之间分配工作,或者可以分布在多个机器上。如果一个Worker中的配置发生了更改,则Flask会无法确保其他Worker之间的一致性。

如果在处理请求后调用了与安装相关的方法,则Flask会显示一个错误,从而帮助开发人员发现其中一些安装顺序问题。在这种情况下,您将看到以下错误:

不能再对应用程序调用Setup方法‘route’。它已经处理了它的第一个请求,任何更改都不会一致地应用。确保在运行应用程序之前完成设置应用程序所需的所有导入、装饰符、函数等。

但是,烧瓶不可能检测到所有无序设置的情况。通常,不要执行任何操作来修改 Flask 应用程序对象和 Blueprint 在请求期间运行的视图函数内的对象。这包括:

  • 使用添加路由、查看函数和其他请求处理程序 @app.route@app.errorhandler@app.before_request

  • 正在登记蓝图。

  • 使用加载配置 app.config

  • 使用设置JJJA模板环境 app.jinja_env

  • 设置会话接口,而不是默认的危险Cookie。

  • 使用设置JSON提供程序 app.json ,而不是默认提供程序。

  • 正在创建和初始化烧瓶扩展。

服务于应用程序

FlASK是一个WSGI应用程序框架。WSGI的另一半是WSGI服务器。在开发过程中,FlaskWerkzeug为开发WSGI服务器提供 flask run CLI命令。完成开发后,使用生产服务器为应用程序提供服务,请参见 部署到生产环境

无论您使用的是哪种服务器,它都将遵循 PEP 3333 WSGI规范。WSGI服务器将被告知如何访问您的FlASK应用程序对象,即WSGI应用程序。然后,它将开始侦听HTTP请求,将请求数据转换为WSGI环境,并使用该数据调用WSGI应用程序。WSGI应用程序将返回被转换为HTTP响应的数据。

  1. 浏览器或其他客户端发出HTTP请求。

  2. WSGI服务器接收请求。

  3. WSGI服务器将HTTP数据转换为WSGI environ 迪克特。

  4. WSGI服务器使用 environ

  5. WSGI应用程序FASK执行其所有内部处理,以将请求路由到视图函数、处理错误等。

  6. FLAASK将View函数返回转换为WSGI响应数据,并传递给WSGI服务器。

  7. WSGI服务器创建并发送一个HTTP响应。

  8. 客户端收到该HTTP响应。

中间件

上面的WSGI应用程序是一个以特定方式运行的可调用程序。中间件是包装另一个WSGI应用程序的WSGI应用程序。这是一个类似于Python装饰器的概念。最外层的中间件将由服务器调用。它可以修改传递给它的数据,然后调用它包装的WSGI应用程序(或其他中间件),依此类推。它可以获取该调用的返回值,并对其进行进一步修改。

从WSGI服务器的角度来看,有一个它直接调用的WSGI应用程序。通常,FlaskTM是中间件链末端的“真正的”应用程序。但是,即使是Flask也可以调用更多的WSGI应用程序,尽管这是一个高级的、不常见的用例。

您将看到Flask中使用的一个常见中间件是Werkzeug ProxyFix ,它将请求修改为看起来像是直接来自客户端的请求,即使它在途中通过了HTTP代理。还有其他中间件可以处理服务静态文件、身份验证等。

如何处理请求

对我们来说,上述步骤中有趣的部分是当WSGI服务器(或中间件)调用Flask时。在这一点上,它将在处理请求和生成响应方面做很多工作。在最基本的情况下,它会将URL与view函数相匹配,调用view函数,并将返回值传递回服务器。但是,您还可以使用更多的部分来自定义其行为。

  1. WSGI服务器调用Flask对象,该对象调用 Flask.wsgi_app()

  2. A RequestContext 对象已创建。这会将WSGI environ 把词典译成一本 Request 对象。它还创建了一个 AppContext 对象。

  3. 这个 app context 是按下的,这使得 current_appg 可用。

  4. 这个 appcontext_pushed 信号已发送。

  5. 这个 request context 是按下的,这使得 requestsession 可用。

  6. 会话将打开,并使用应用程序的加载任何现有会话数据 session_interface ,一个实例 SessionInterface

  7. 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. 请求上下文被弹出, requestsession 不再可用。

  24. 任何 teardown_appcontext() 调用修饰函数。

  25. 这个 appcontext_tearing_down 信号已发送。

  26. 弹出应用程序上下文, current_appg 不再可用。

  27. 这个 appcontext_popped 信号已发送。

甚至还有比这更多的装饰器和定制点,但这并不是每个请求生命周期的一部分。它们更特定于您在请求期间可能使用的某些东西,例如模板、构建URL或处理JSON数据。请参阅本文档的其余部分,以及 API 以进一步探索。