概述
在使用 Flask 的过程中,有一项很舒服的功能不知道小伙伴们有没有发现,那么就是我们写 View 的时候居然不用传递 request
和 response
变量,例如直接这些写就好了:
图 1:flask 使用示例 |
但是,用过 Django 和 Tornado 的同学也都知道,在 Django 中是需要我们自己传递 request
对象的,就像这样:
图 2:request 对象 |
Tornado 里面虽然没有传递这样的 Request 变量,但是,Tornado 却是需要集成自 RequestHandler
类,其实也就是变相得传递了。
那么为什么都是 Web 框架,而 Flask 却可以做到不需要传递 request
呢?这其实就是这篇文章要解析得 Context 上下文。而且这个 Context 不仅影响 request
, 还会影响全局变量 g
和一些参数。
什么是上下文
从 Flask 的官方文档中,我们可以发现在 Flask 中,Context 分为两类,分别是 AppContext 和 RequestContext。其中 RequestCntext
是只针对于单次请求有效的,也就是我们常用的 request
和 session
这类;另外一种 AppContext
是针对于整个应用周期的,可以理解为 Flask 的 Web 应用一启动就有,关闭就结束的一种 Context,例如我们常用的 g
和 current_app
变量这一类。
Context 如何起作用
为了理解 Context
是如何起作用的,我们还是来跟踪一下源代码看看,打开 flask/globals.py
这个文件,可以看到以下的内容:
flask/globals.py
图 3:Context 实现 |
这里可以发现,所有的这些变量都跟 Stack
有关,而Stack
也分为两种,分别是:
line 56: _request_ctx_stack = LocalStack()
line 57: _app_ctx_stack = LocalStack()
何时入栈 出栈
flask/app.py
line 1936: def wsgi_app(self, environ, start_response):
... ...
line 1961: ctx = self.request_context(environ)
line 1961: ctx.push()
line 1961: error = None
line 1961: try:
line 1961: try:
line 1961: response = self.full_dispatch_request()
line 1961: except Exception as e:
line 1961: error = e
line 1961: response = self.make_response(self.handle_exception(e))
line 1961: return response(environ, start_response)
line 1961: finally:
line 1961: if self.should_ignore_error(error):
line 1961: error = None
line 1961: ctx.auto_pop(error)
这里可以发现其实是每次请求过来的时候就入栈了,然后请求完成之后就出栈了。
有没有可能栈里面有多个元素
栈里面不会出现多个元素,但是,在调试模式下,可能在一个请求出错之后元素不会出栈,代码在:
flask/ctx.py
line 377: def auto_pop(self, exc):
line 378: if self.request.environ.get('flask._preserve_context') or \
line 379: (exc is not None and self.app.preserve_context_on_exception):
line 380: self.preserved = True
line 381: self._preserved_exc = exc
line 382: else:
line 383: self.pop(exc)
然后在下一次的请求入栈前先出栈
line 297: def push(self):
... ...
line 307: top = _request_ctx_stack.top
line 308: if top is not None and top.preserved:
line 309: top.pop(top._preserved_exc)
遗留问题:如果不会出现多个元素干嘛要用栈?
Context 里面有什么内容
- RequestContext
- request context 包含所有请求相关的信息。
- 可以直接使用的有:
- app
- request
- url_adapter
- flashes
- session