深入理解flask框架(2):应用上下文与请求上下文
2017-12-29 12:01
1266 查看
什么是上下文?
flask框架中的上下文本质上就是两个类,我们可以先看一下他的初始化函数:应用上下文
class AppContext(object): """The application context binds an application object implicitly to the current thread or greenlet, similar to how the :class:`RequestContext` binds request information. The application context is also implicitly created if a request context is created but the application is not on top of the individual application context. """ def __init__(self, app): self.app = app self.url_adapter = app.create_url_adapter(None) self.g = app.app_ctx_globals_class() # Like request context, app contexts can be pushed multiple times # but there a basic "refcount" is enough to track them. self._refcnt = 0
请求上下文
class RequestContext(object): def __init__(self, app, environ, request=None): self.app = app if request is None: request = app.request_class(environ) self.request = request self.url_adapter = app.create_url_adapter(self.request) self.flashes = None self.session = None self._implicit_app_ctx_stack = [] self.preserved = False self._preserved_exc = None self._after_request_functions = [] self.match_request()
为什么设计上下文这样的机制?
详细解释可参考:https://blog.tonyseek.com/post/the-context-mechanism-of-flask/
- 为了实现线程之间的隔离
类似Thread Local ,每个线程对一个 Thread Local 对象的修改都不会影响其他线程。这种对象的实现原理也非常简单,只要以线程的 ID 来保存多份状态字典即可,就像按照门牌号隔开的一格一格的信箱。
为了实现一个 Python 进程中拥有多个应用
from werkzeug.wsgi import DispatcherMiddleware from biubiu.app import create_app from biubiu.admin.app import create_app as create_admin_app application = DispatcherMiddleware(create_app(), { '/admin': create_admin_app() })
上下文机制依赖的数据结构
flask上下文机制的实现基于 Werkzeug 的 Local Stack 实现。阅读源码,我们发现Local类的本质是一个字典和一个获取到线程id的函数。
class Local(object): __slots__ = ('__storage__', '__ident_func__') def __init__(self): object.__setattr__(self, '__storage__', {}) object.__setattr__(self, '__ident_func__', get_ident)
而LocalStack在Local类的基础上又实现了栈的功能。
class LocalStack(object): def __init__(self): self._local = Local()
flask中应用上下文栈和请求上下文栈正是基于上面的LocalStack类
_request_ctx_stack = LocalStack() _app_ctx_stack = LocalStack()
下面我们通过一些实验来进一步学习flask的执行过程:
In [1]: from flask.globals import _app_ctx_stack, _request_ctx_stack In [2]: from flask import Flask In [3]: app = Flask(__name__) In [4]: _app_ctx_stack._local.__storage__ Out[4]: {} In [5]: _request_ctx_stack._local.__storage__ Out[5]: {} In [6]: req_ctx = app.test_request_context() In [7]: req_ctx.push() In [8]: _request_ctx_stack._local.__storage__ Out[8]: {<greenlet.greenlet at 0x7f69d45b8f20>: {'stack': [<RequestContext 'http://localhost/' [GET] of __main__>]}} In [9]: _app_ctx_stack._local.__storage__ Out[9]: {<greenlet.greenlet at 0x7f69d45b8f20>: {'stack': [<flask.ctx.AppContext at 0x7f69d4774cf8>]}}
我们可以看到一开始上下文均为空,test_request_context()函数会生成一个请求上下文,我们通过push让它入栈,之后两个上下文都有了内容,为什么_app_ctx_stack中也有内容呢?
我们可以看一下源码,第一次请求上下文push时,app_ctx如果为None,就会调用implicit_app_ctx_stack添加一个应用上下文。
app_ctx = _app_ctx_stack.top if app_ctx is None or app_ctx.app != self.app: app_ctx = self.app.app_context() app_ctx.push() self._implicit_app_ctx_stack.append(app_ctx) else: self._implicit_app_ctx_stack.append(None)
这里我们就可以解释wsgi_app这部分代码,每次web服务器提供了environ变量,就会创建一个request_context对象,push()
之后就会进入_request_ctx_stack中,并在执行处理函数之后会自动pop,
所以我们说请求上下文的生命周期就是一次请求的过程。
def wsgi_app(self, environ, start_response): ctx = self.request_context(environ) error = None try: try: ctx.push() response = self.full_dispatch_request() except Exception as e: error = e response = self.handle_exception(e) except: error = sys.exc_info()[1] raise return response(environ, start_response) finally: if self.should_ignore_error(error): error = None ctx.auto_pop(error)
整体流程可参考:
https://www.jianshu.com/p/2a2407f66438
相关文章推荐
- 深入理解flask框架(1):WSGI与路由
- 深入理解Nginx chap 4 配置, error日志和请求上下文
- 深入理解flask框架(3):config与extension
- 源码剖析.Python.深入源码剖析Flask程序请求上下文?
- 深入理解Java Proxy机制 应用在 Hadoop RPC 框架
- 三滴水:光说不练假把式,Flask关于请求表单的粗浅应用及理解+简单SQL语句温习
- iOS开发CoreGraphics核心图形框架之二——深入理解图形上下文
- 深入理解Flask中的上下文
- 深入理解flask框架(4):session
- flask基础之AppContext应用上下文和RequestContext请求上下文(六)
- 读《深入理解Windows Phone 8.1 UI控件编程》1.4.3 框架的应用示例:自定义弹出窗口有感
- Flask进阶(一)——请求上下文和应用上下文完全解答(上)
- Flask进阶(一)——请求上下文和应用上下文完全解答(下)
- Flask-应用(程序)上下文和请求上下文
- boost asio 应用方法学(二)——深入框架
- 深入理解javascript(13):作用域和执行上下文
- 深入理解与应用Hadoop中的MapReduce
- Javascript中的作用域和上下文深入理解
- 深入理解CSS中的层叠上下文和层叠顺序
- 深入理解IOC模式及Unity框架