流程图:
最近在看flask源码学习下flask工作原理,然后就尝试着画了个流程图,如上图所示,部分功能细节可能没有写上去,有什么遗漏的地方欢迎大家补充。
WSGI:
全称是Web Server Gateway Interface,WSGI不是服务器,python模块,框架,API或者任何软件,只是一种规范,描述web server如何与web application通信的规范。server和application的规范在PEP 3333中有具体描述。要实现WSGI协议,必须同时实现web server和web application,当前运行在WSGI协议之上的web框架有Torando,Flask,Django, Flask 基于werkzeug 库,而werkzeug则是对WSGI 具体的实现
Flask中的上下文
flask中实现了上下文的变量共有,如下图所示,分别是current_app、request、session、g
current_app: 当前应用环境上下文
request: 当前请求上下文,每个请求上下文都有一个专门对应的应用上下文
session: 用于管理当前请求的session
g: 与当前应用上下关联的全局变量
1、flask处理不同请求之间是如何实现隔离的?
前面有介绍Flask主要是借助werkzueg来实现的,其中请求之间隔离的方式借助了库中Local、LocalStack、LocalProxy 三个类
Local:
首先local添加了一个__storage__字典用来存储添加的属性,当给local对象进行添加属性会自动根据get_ident方法获取当前的线程、进程,键为线程、进程ID号,值为添加的属性,同理当取值时,会自动判断当前的环境来取值, 类似于threading中的local
LocalStack:
LocalStack基于local实现了一个‘先进晚出’的栈结构,内部通过为每个线程、进程添加
stack属性来存储数据,存储数据的容器为list,值得注意是每次添加值、取值得时候内部会自动判断当前的线程、进程环境为每个线程、进程床架一个单独的容器,这也是不同请求之间实现隔离的主要原因,同样的current_app 当前的应用上下文也用到了类似的方式来管理,也就是说每个请求都有自己的应用上下文,请求的每次入栈都会判断当前的应用上下文,如果没有创建应用上下文,则创建对应的上下文压入栈也就是_app_ctx_stack,request对应的则是_request_ctx_stack,如下图所示
LocalProxy:
通过查看源码发现,LocalProxy实现了重写了大量的类的‘魔术’方法,其实localproxy主要就是对对象、方法进行了包装,通过localproxy进行过渡可以直接操作目标对象
如上图所示,LocalProxy对_lookup_req_object方法进行了包装,当我们访问request属性的时候,由于LocalProxy重写了__setattr__ __getattr__等特殊方法,如下图所示
在执行的时候会调用_get_cuurent_object方法,如下图所示
这里直接执行了self.__local()方法其实也就是包装之前的_lookup_req_object,通过这个方法可以获取全局请求上下文栈顶的请求上下文中的request属性,注意_request_ctx_stack中存储的是请求上下文(Request_Context),我们每次操作的request其实是Request_Context的一个属性
使用LocalProxy的好处是啥? 不用可不可以?
答: 可以,只不过操作起来会很痛苦,拿上述代码举例,每次获取当前环境的请求将是这样的
req_context = _lookup_req_object()
request = req_context.request
然后我们才可以通过request进行取值、赋值等操作,显然这样的方式更痛苦,LocalProxy将这部分代码进行了复用,操作起来也更加的简洁、直观;