应用程序结构和生命周期¶
Flask 使编写 Web 应用程序变得非常容易。但是,应用程序及其处理的每个请求都有很多不同的部分。了解应用程序设置、服务和处理请求期间发生的情况将帮助你了解 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
应用程序对象和 Blueprint
对象进行任何修改。这包括
使用
@app.route
、@app.errorhandler
、@app.before_request
等添加路由、视图函数和其他请求处理程序。注册蓝图。
使用
app.config
加载配置。使用
app.jinja_env
设置 Jinja 模板环境。设置会话接口,而不是默认的 itsdangerous cookie。
使用
app.json
设置 JSON 提供程序,而不是默认提供程序。创建并初始化 Flask 扩展。
提供应用程序¶
Flask 是 WSGI 应用程序框架。WSGI 的另一半是 WSGI 服务器。在开发期间,Flask 通过 Werkzeug 提供一个开发 WSGI 服务器,使用 flask run
CLI 命令。当您完成开发后,使用生产服务器来提供您的应用程序,请参见 部署到生产环境。
无论您使用什么服务器,它都将遵循 PEP 3333 WSGI 规范。WSGI 服务器将被告知如何访问您的 Flask 应用程序对象,即 WSGI 应用程序。然后,它将开始侦听 HTTP 请求,将请求数据转换为 WSGI environ
,并使用该数据调用 WSGI 应用程序。WSGI 应用程序将返回转换为 HTTP 响应的数据。
浏览器或其他客户端发出 HTTP 请求。
WSGI 服务器接收请求。
WSGI 服务器将 HTTP 数据转换为 WSGI
environ
字典。WSGI 服务器使用
environ
调用 WSGI 应用程序。WSGI 应用程序 Flask 执行其所有内部处理,以将请求路由到视图函数、处理错误等。
Flask 将视图函数返回转换为 WSGI 响应数据,并将其传递给 WSGI 服务器。
WSGI 服务器创建并发送 HTTP 响应。
客户端接收 HTTP 响应。
中间件¶
上述 WSGI 应用程序是一个以特定方式表现的可调用对象。中间件是一个包装另一个 WSGI 应用程序的 WSGI 应用程序。它与 Python 装饰器类似。最外层的中间件将由服务器调用。它可以修改传递给它的数据,然后调用它包装的 WSGI 应用程序(或进一步的中间件),依此类推。它还可以获取该调用的返回值并进一步修改它。
从 WSGI 服务器的角度来看,只有一个 WSGI 应用程序,即它直接调用的应用程序。通常,Flask 是中间件链末端的“真实”应用程序。但即使是 Flask 也可以调用其他 WSGI 应用程序,尽管这是一个高级的、不常见的用例。
你会看到与 Flask 一起使用的常见中间件是 Werkzeug 的 ProxyFix
,它修改请求以使其看起来像直接来自客户端,即使它在途中经过了 HTTP 代理。还有其他中间件可以处理静态文件、身份验证等的提供。
请求的处理方式¶
对我们来说,上述步骤中有趣的部分是当 Flask 被 WSGI 服务器(或中间件)调用时。在这一点上,它将做很多事情来处理请求并生成响应。最基本的是,它将 URL 匹配到视图函数,调用视图函数,并将返回值传递回服务器。但还有更多部分可用于自定义其行为。
WSGI 服务器调用 Flask 对象,该对象调用
Flask.wsgi_app()
。创建了
RequestContext
对象。这将 WSGIenviron
字典转换为Request
对象。它还创建了一个AppContext
对象。推送 应用程序上下文,这使得
current_app
和g
可用。发送
appcontext_pushed
信号。会话已打开,使用应用的
session_interface
加载任何现有的会话数据,它是SessionInterface
的一个实例。URL 与在应用设置期间使用
route()
装饰器注册的 URL 规则进行匹配。如果没有匹配项,则将错误(通常是 404、405 或重定向)存储起来,以便稍后处理。发送
request_started
信号。调用任何
url_value_preprocessor()
装饰函数。调用任何
before_request()
装饰函数。如果这些函数中的任何一个返回一个值,则立即将其视为响应。如果 URL 在几步之前与某个路由不匹配,则现在将引发该错误。
调用与匹配的 URL 关联的
route()
装饰视图函数,并返回一个用作响应的值。如果到目前为止任何步骤引发了异常,并且有一个
errorhandler()
装饰函数与异常类或 HTTP 错误代码匹配,则调用该函数来处理错误并返回响应。无论哪个返回响应值(请求前函数、视图或错误处理程序),该值都会转换为
Response
对象。调用任何
after_this_request()
装饰函数,然后清除它们。调用任何
after_request()
装饰函数,这些函数可以修改响应对象。会话已保存,使用应用的
session_interface
来保留任何修改后的会话数据。发送
request_finished
信号。如果到目前为止的任何步骤引发了异常,并且它未由错误处理程序函数处理,则现在将对其进行处理。HTTP 异常将被视为具有相应状态代码的响应,其他异常将被转换为通用 500 响应。发送
got_request_exception
信号。响应对象的状态、标题和正文将返回到 WSGI 服务器。
调用任何
teardown_request()
装饰的函数。发送
request_tearing_down
信号。调用任何
teardown_appcontext()
装饰的函数。发送
appcontext_tearing_down
信号。弹出应用上下文,
current_app
和g
不再可用。发送
appcontext_popped
信号。
还有更多装饰器和自定义点,但这并不是每个请求生命周期的一部分。它们更具体地针对您在请求期间可能使用的一些内容,例如模板、构建 URL 或处理 JSON 数据。请参阅本文档的其余部分以及 API 以进一步了解。