应用程序结构和生命周期¶
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响应的数据。
浏览器或其他客户端发出HTTP请求。
WSGI服务器接收请求。
WSGI服务器将HTTP数据转换为WSGI
environ
迪克特。WSGI服务器使用
environ
。WSGI应用程序FASK执行其所有内部处理,以将请求路由到视图函数、处理错误等。
FLAASK将View函数返回转换为WSGI响应数据,并传递给WSGI服务器。
WSGI服务器创建并发送一个HTTP响应。
客户端收到该HTTP响应。
中间件¶
上面的WSGI应用程序是一个以特定方式运行的可调用程序。中间件是包装另一个WSGI应用程序的WSGI应用程序。这是一个类似于Python装饰器的概念。最外层的中间件将由服务器调用。它可以修改传递给它的数据,然后调用它包装的WSGI应用程序(或其他中间件),依此类推。它可以获取该调用的返回值,并对其进行进一步修改。
从WSGI服务器的角度来看,有一个它直接调用的WSGI应用程序。通常,FlaskTM是中间件链末端的“真正的”应用程序。但是,即使是Flask也可以调用更多的WSGI应用程序,尽管这是一个高级的、不常见的用例。
您将看到Flask中使用的一个常见中间件是Werkzeug ProxyFix
,它将请求修改为看起来像是直接来自客户端的请求,即使它在途中通过了HTTP代理。还有其他中间件可以处理服务静态文件、身份验证等。
如何处理请求¶
对我们来说,上述步骤中有趣的部分是当WSGI服务器(或中间件)调用Flask时。在这一点上,它将在处理请求和生成响应方面做很多工作。在最基本的情况下,它会将URL与view函数相匹配,调用view函数,并将返回值传递回服务器。但是,您还可以使用更多的部分来自定义其行为。
WSGI服务器调用Flask对象,该对象调用
Flask.wsgi_app()
。A
RequestContext
对象已创建。这会将WSGIenviron
把词典译成一本Request
对象。它还创建了一个AppContext
对象。这个 app context 是按下的,这使得
current_app
和g
可用。这个
appcontext_pushed
信号已发送。这个 request context 是按下的,这使得
request
和session
可用。会话将打开,并使用应用程序的加载任何现有会话数据
session_interface
,一个实例SessionInterface
。URL与注册到
route()
应用程序设置过程中的装饰器。如果没有匹配,则存储错误--通常是404、405或重定向--以备以后处理。这个
request_started
信号已发送。任何
url_value_preprocessor()
调用修饰函数。任何
before_request()
调用修饰函数。如果这些函数中的任何一个返回值,它将立即被视为响应。如果几个步骤前URL与某个路由不匹配,那么现在就会出现该错误。
这个
route()
调用与匹配的URL相关联的修饰视图函数,并返回要用作响应的值。如果到目前为止的任何步骤引发了异常,并且存在
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 以进一步探索。