flask 源码剖析
上下文本质
- 当请求过来后,将请求相关数据添加到 Local()类中 { 线程或协程唯一标识:{"stack":[request]}, 线程或协程唯一标识:{"stack":[]}, 线程或协程唯一标识:{"stack":[]} } - 以后使用时 去读取 - 请求完成之后,将request从列表中移除
Flask源码
from flask import Flask,session,request app = Flask(__name__) @app.route("/login",methods=["GET","POST"]) def login(): return "index" if __name__ == '__main__': #app.__call__() app.run()
1. 执行app.__call__方法
def __call__(self, environ, start_response): return self.wsgi_app(environ, start_response)
2. 执行wsgi_app方法
def wsgi_app(self, environ, start_response): ctx = self.request_context(environ) ctx.push() response = self.full_dispatch_request()
2.1 生成RequestContext()对象 封装请求相关的数据(request,session)
ctx = self.request_context(environ)
def request_context(self, environ): return RequestContext(self, environ) 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
2.2 将用户请求数据封装到Local()类中
ctx.push()
def push(self): from .globals import _request_ctx_stack #将请求数据封装到Local()类 _request_ctx_stack.push(self) #处理session self.session = self.app.open_session(self.request) if self.session is None: self.session = self.app.make_null_session()
2.2.1 导入 _request_ctx_stack对象 内部会自动生成 { 线程或协程唯一标识:{"stack":[]} } 格式
from .globals import _request_ctx_stack
class Local(object): def __init__(self): object.__setattr__(self, '__storage__', {}) object.__setattr__(self, '__ident_func__', get_ident) def __setattr__(self, name, value): ident = self.__ident_func__() storage = self.__storage__ try: storage[ident][name] = value except KeyError: storage[ident] = {name: value} class LocalStack(object): def __init__(self): self._local = Local() def push(self, obj): rv = getattr(self._local, 'stack', None) if rv is None: self._local.stack = rv = [] rv.append(obj) return rv _request_ctx_stack = LocalStack()
2.2.2 执行_request_ctx_stack对象push方法 触发Local的__setattr__执行 生成 { 线程或协程唯一标识:{"stack":[ RequestContext对象 ]} }
_request_ctx_stack.push(self)
class Local(object): def __setattr__(self, name, value): ident = self.__ident_func__() storage = self.__storage__ try: storage[ident][name] = value except KeyError: storage[ident] = {name: value} class LocalStack(object): def push(self, obj): """Pushes a new item to the stack""" rv = getattr(self._local, 'stack', None) if rv is None: self._local.stack = rv = [] rv.append(obj) return rv _request_ctx_stack = LocalStack()
2.2.3 self.session重新赋值
RequestContext类的 self.session由none重新赋值为SecureCookieSessionInterface类open_session方法的结果(SecureCookieSession对象) - SecureCookieSession对象 就是一个字典 self.session = self.app.open_session(self.request)
def open_session(self, request): return self.session_interface.open_session(self, request) # 之后这里可以自定义自己类 可以继承SecureCookieSessionInterface类 session_interface = SecureCookieSessionInterface() class SecureCookieSessionInterface(SessionInterface): def open_session(self, app, request): s = self.get_signing_serializer(app) if s is None: return None # 去cookie中获取session作为key 对应的值(包含了此用户的session数据) val = request.cookies.get(app.session_cookie_name) if not val: return self.session_class() max_age = total_seconds(app.permanent_session_lifetime) try: data = s.loads(val, max_age=max_age) return self.session_class(data) except BadSignature: return self.session_class()
3. 之后调用request
#此时你如果调用request 会执行如下代码 request = LocalProxy(partial(_lookup_req_object, 'request')) _lookup_req_object 获取RequestContext()中用户的请求数据
4. 执行视图函数
response = self.full_dispatch_request()
4.1 触发只执行一次的装饰器函数 @before_first_request
self.try_trigger_before_first_request_functions()
4.2 # 触发Flask的信号 需要pip3 install blinker
request_started.send(self)
4.3 执行特殊装饰器 @before_request
有返回值 返回用户 没有返回值 触发并执行视图函数 rv = self.preprocess_request() if rv is None: rv = self.dispatch_request()
4.4 执行请求之后的装饰器 @after_request 且处理session
return self.finalize_request(rv) def finalize_request(self, rv, from_error_handler=False): response = self.process_response(response) def process_response(self, response): # 处理session if not self.session_interface.is_null_session(ctx.session): self.save_session(ctx.session, response)