请求上下文在请求期间跟踪请求级数据。而不是将请求对象传递给在请求期间运行的每个函数,而是访问 request 和 会话 代理。
这类似于应用程序上下文,它独立于请求跟踪应用程序级数据。当推送请求上下文时,推送相应的应用程序上下文。
上下文的目的
当 Flask 应用程序处理请求时,它会根据从WSGI服务器收到的环境创建一个 Request 对象。由于worker(线程,进程或协程取决于服务器)一次只处理一个请求,因此在该请求期间可以将请求数据视为该工作者的全局请求。Flask为此使用术语context local。
Flask在处理请求时自动推送请求上下文。查看函数,错误处理程序以及在请求期间运行的其他函数将有权访问 request 代理,该代理指向当前请求的请求对象。
上下文的生命周期
当Flask应用程序开始处理请求时,它会push请求上下文,这也会push 应用程序上下文 。当请求结束时,它会pop请求上下文,然后pop应用程序上下文。
上下文对于每个线程(或其他worker类型)是唯一的。request 无法传递给另一个线程,另一个线程将具有不同的上下文堆栈,并且不会知道父线程指向的请求。
上下文本地在Werkzeug中实现。有关其内部工作原理的更多信息,请参阅上下文本地。
手动推送上下文
如果您尝试在请求上下文之外访问请求或使用它的任何内容,您将收到以下错误消息:
|
|
通常只有在测试需要active请求的代码时才会发生这种情况。一种选择是使用test client 来模拟完整请求。或者,您可以在with块中使用test_request_context() ,并且块中运行的所有内容都可以访问请求 ,并填充测试数据。
|
|
如果您在代码中的其他位置看到与测试无关的错误,则很可能表示您应该将该代码移动到视图函数中。
有关如何使用交互式Python shell中的请求上下文的信息,请参阅使用命令行管理程序。
上下文如何运作
调用Flask.wsgi_app()方法来处理每个请求。它在请求期间管理上下文。在内部,请求和应用程序上下文用作堆栈,_request_ctx_stack 和_app_ctx_stack 。当上下文被压入堆栈时,依赖于它们的代理是可用的,并指向来自堆栈顶部上下文的信息
当请求开始时,创建并pushed RequestContext,如果该应用程序的上下文不是顶层上下文,则首先创建并pushes AppContext。在推送这些上下文时,current_app,g,request和session代理可用于处理请求的原始线程。
因为上下文是堆栈,所以可以推送其他上下文以在请求期间更改代理。虽然这不是一种常见的模式,但它可以在高级应用程序中使用,例如,进行内部重定向或将不同的应用程序链接在一起。
在调度请求并生成并发送响应之后,将poped请求上下文,然后popped应用程序上下文。在popped它们之前,执行teardown_request() 和teardown_appcontext() 函数。即使在发送期间发生未处理的异常,它们也会执行。
回调和错误
Flask在多个阶段调度请求,这可能会影响请求,响应以及如何处理错误。在所有这些阶段中,上下文都是活跃的。
Blueprint 可以为这些特定于blueprint的事件添加处理程序。如果blueprint拥有与请求匹配的路由,则将运行blueprint处理程序。
- 在每个请求之前,调用before_request() 函数。如果其中一个函数返回一个值,则跳过其他函数。返回值被视为响应,并且不调用视图函数。
- 如果before_request()函数未返回响应,则调用匹配路由的视图函数并返回响应。
- 视图的返回值将转换为实际响应对象并传递给after_request()函数。每个函数都返回一个修改的或新的响应对象。
- 返回响应后,弹出上下文,调用teardown_request()和teardown_appcontext()函数。即使在上面的任何点引发了未处理的异常,也会调用这些函数。
如果在拆卸函数之前引发异常,Flask会尝试将其与errorhandler()函数匹配以处理异常并返回响应。如果未找到错误处理程序,或者处理程序本身引发异常,Flask将返回通用的500内部服务器错误
响应。仍然会调用拆卸函数,并传递异常对象。
如果启用了调试模式,则未处理的异常不会转换为500
响应,而是传播到WSGI服务器。这允许开发服务器向交互式调试器提供回溯。
Teardown回调
teardown回调与请求分派无关,而是在popped时由上下文调用。即使在调度期间存在未处理的异常,也会调用函数,以及手动推送的上下文。这意味着无法保证请求调度的任何其他部分首先运行。请务必以不依赖于其他回调的方式编写这些函数,并且不会失败。
在测试期间,在请求结束后推迟popped上下文可能很有用,这样可以在测试函数中访问它们的数据。使用test_client()作为with块来保留上下文,直到with块退出。
|
|
Signals
如果signals_available为true,则发送以下信号:
- request_started 在调用before_request() 函数之前发送。
- 在调用after_request()函数之后发送request_finished。
- 在开始处理异常时,但在查找或调用errorhandler() 之前发送got_request_exception 。
- 在调用teardown_request() 函数之后发送request_tearing_down 。
上下文保留错误
在请求结束时,将popped请求上下文,并销毁与其关联的所有数据。如果在开发过程中发生错误,则延迟销毁数据以进行调试非常有用。
当开发服务器以开发模式运行时(FLASK_ENV
环境变量设置为'development'
),错误和数据将被保留并显示在交互式调试器中。
可以使用 PRESERVE_CONTEXT_ON_EXCEPTION 配置控制此行为。如上所述,它在开发环境中默认为True
。
不要在生产中启用 PRESERVE_CONTEXT_ON_EXCEPTION ,因为它会导致应用程序在异常时泄漏内存。
关于代理的注意事项
Flask提供的一些对象是其他对象的代理。对于每个工作线程,代理以相同的方式访问,但指向此页面中描述的绑定到幕后每个worker的唯一对象。
大多数情况下你不必关心它,但有一些例外情况,知道这个对象是一个真正的代理是很好的:
- 代理对象不能伪造其类型作为实际对象类型。如果要执行实例检查,则必须对要代理的对象执行此操作。
- 如果特定对象引用很重要,例如发送信号或将数据传递给后台线程。
如果需要访问代理的基础对象,请使用_get_current_object()方法:
|
|