Flask框架整个流程源码解读 一.总的流程 运行Flask其本质是运行Flask对象中的__call__,而 __call__ 本质调用wsgi_app的方法 wsgi_app方法 def wsgi_app(self, environ, start_response): #1.ctx是ResquestContext的对象
Flask框架整个流程源码解读
一.总的流程
运行Flask其本质是运行Flask对象中的__call__,而__call__
本质调用wsgi_app的方法
wsgi_app方法
def wsgi_app(self, environ, start_response): #1.ctx是ResquestContext的对象,里面request ctx = self.request_context(environ) error = None try: try: #2.就是ctx放到了Local对象 ctx.push() #3.所有请求的执行函数的,包括请求扩展,真正的视图函数 response = self.full_dispatch_request() except Exception as e: error = e response = self.handle_exception(e) except: # noqa: B001 error = sys.exc_info()[1] raise #3. 请求之后的函数 return response(environ, start_response) finally: if self.should_ignore_error(error): error = None #4.最后把对应的request在request的队列中删除 ctx.auto_pop(error)
二.具体流程
1.ctx = self.request_context(environ) environ
请求相关的,ctx现在是包含request,session的RequestContext的对象
源码
1.1RequestContext(self, environ) self ,是app对象 environ,请求相关的 1.2 RequestContext在实例化的时候的源码: def __init__(self, app, environ, request=None, session=None): self.app = app if request is None: request = app.request_class(environ) self.request = request self.url_adapter = None try: self.url_adapter = app.create_url_adapter(self.request) except HTTPException as e: self.request.routing_exception = e self.flashes = None self.session = session self._implicit_app_ctx_stack = [] self.preserved = False self._after_request_functions = [] #这个RequestContext对象封装了,request 和seesoin
2.ctx.push()
这个ctx是RequestContext,那就执行RequestContext.push方法
2.1RequestContext.push()的源码
def push(self): #_request_ctx_stack是localStack的对象 #self是ctx,把self也就ctx放入到local对象里面 top = _request_ctx_stack.top if top is not None and top.preserved: top.pop(top._preserved_exc) 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) if hasattr(sys, "exc_clear"): sys.exc_clear() _request_ctx_stack.push(self) #这个里面的push源码如下 if self.session is None: session_interface = self.app.session_interface self.session = session_interface.open_session(self.app, self.request) if self.session is None: self.session = session_interface.make_null_session(self.app) if self.url_adapter is not None: self.match_request()
源码中的push的源码
#obj是ctx def push(self, obj): #obj是ctx,requestContext的对象 rv = getattr(self._local, "stack", None) if rv is None: self._local.stack = rv = [] rv.append(obj) return rv ''' 2.1.1 _request_ctx_stack.push(self)现在的self是ctx 2.1.2 _request_ctx_stack是LocalStack()的对象 2.1.3 LocalStack()的push把ctx传过来 2.1.4 LocalStack()的push方法 最终也就是ctx.push()他的最终目的:把当前的ctx放入到Local()里面 '''
3 response = self.full_dispatch_request()
源码
#这是服务器第一次请求时候执行的函数 self.try_trigger_before_first_request_functions() try: request_started.send(self) #执行请求之前所有的函数,并且拿到请求之前的返回值 rv = self.preprocess_request() if rv is None: #这个是真正视图函数,如果我的请求之前函数没有返回值才会执行 rv = self.dispatch_request() except Exception as e: rv = self.handle_user_exception(e) return self.finalize_request(rv) 3.1 return self.finalize_request(rv)的源码: def finalize_request(self, rv, from_error_handler=False): response = self.make_response(rv) try: #请求之后的函数,after_request response = self.process_response(response) request_finished.send(self, response=response) except Exception: if not from_error_handler: raise self.logger.exception( "Request finalizing failed with an error while handling an error" ) return response
- 告诉我们了几个函数的运行顺序
- 解释了为什么frist_request为什么只第一次启动项目页面才会运行,因为运行后值就不为空后面事物也不走first相关函数了
也解释了为什么before_request有返回值后就不会运行真正的视图,因为有返回值后rv就不为空了就不运行下面的函数
同样我们如果顶进去process_response的相关函数可以看出来他必须要传入response的对象以及返回response的对象
4.我们第三步的任意一个地方都能使用我们的request,session是怎么获取的?
4.1 我们在flask导入request,这个request是一个全局的变量,我们怎么通过request区分我当前的request对象(environ) 我们发现request是LocalProxy的对象 4.2 当我们用全局的request.属性的时候,就会去找LocalProxy的对象,但是我们发现里面根本就没有 那他一定执行LocalProxy对象的__getattr__方法 4.3 我们现在来看LocalProxy对象的__getattr__方法的源码: #name我们要获取属性名 def __getattr__(self, name): if name == "__members__": return dir(self._get_current_object()) #form #self._get_current_object()就是ctx里面的request, return getattr(self._get_current_object(), name) 4.3.1 通过反射self._get_current_object()对象,来找我们属性,也就是name self._get_current_object()的源码: def _get_current_object(self): if not hasattr(self.__local, "__release_local__"): return self.__local() try: #self.__local就实例化传过来的偏函数, return getattr(self.__local, self.__name__) except AttributeError: raise RuntimeError("no object bound to %s" % self.__name__) 4.3.1.1 return getattr(self.__local, self.__name__)那这里self.__local是谁? def __init__(self, local, name=None): object.__setattr__(self, "_LocalProxy__local", local) self.___local为local 这个local为实例化的时候传的 4.3.1.1.1 这个实例化的时候的操作 request = LocalProxy(partial(_lookup_req_object, "request")) 4.3.1.1的local就是 partial(_lookup_req_object, "request")的地址 4.3.1.1.2 _lookup_req_object的源码: #调用的时候 partial(_lookup_req_object, "request") #现在的name就是"request" def _lookup_req_object(name): # top是当前线程的ctx top = _request_ctx_stack.top if top is None: raise RuntimeError(_request_ctx_err_msg) #找top里面的request # ctx找request return getattr(top, name) 4.3.1.1.2 我们来看这个_request_ctx_stack.top的top方法 def top(self): try: return self._local.stack[-1] except (AttributeError, IndexError): return None 我们发现这个self._local是Local()对象,这样就把ctx拿到了