概述
在使用 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 = Noneline 1961: try:line 1961: try:line 1961: response = self.full_dispatch_request()line 1961: except Exception as e:line 1961: error = eline 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 = Noneline 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 = Trueline 381: self._preserved_exc = excline 382: else:line 383: self.pop(exc)
然后在下一次的请求入栈前先出栈
line 297: def push(self):... ...line 307: top = _request_ctx_stack.topline 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