from flask import Flask,request,session app = Flask(__name__) @app.route(‘/index‘) def index(): # 1. request是LocalProxy对象 # 2. 对象中有method、执行__getattr__ print(request.method) # request[‘method‘] # request + 1 # 1. session是LocalProxy对象 # 2. LocalProxy对象的__setitem__ session[‘x‘] = 123 return "Index" if __name__ == ‘__main__‘: app.run() # app.__call__ # app.wsgi_app """ 第一阶段:请求到来 将request和Session相关数据封装到ctx=RequestContext对象中。 再通过LocalStack将ctx添加到Local中。 __storage__ = { 1231:{‘stack‘:[ctx(request,session)]} } 第二阶段:视图函数中获取request或session 方式一:直接找LocalStack获取 from flask.globals import _request_ctx_stack print(_request_ctx_stack.top.request.method) 方式二:通过代理LocalProxy(哈哈)获取 from flask import Flask,request print(request.method) """
https://www.cnblogs.com/Zzbj/p/10207128.html
_request_ctx_stack = LocalStack() _app_ctx_stack = LocalStack() current_app = LocalProxy(_find_app) #local就是我们的partial(_lookup_req_object, "request") request = LocalProxy(partial(_lookup_req_object, "request")) session = LocalProxy(partial(_lookup_req_object, "session")) g = LocalProxy(partial(_lookup_app_object, "g"))
self.wsgi_app(environ, start_response)源码: def wsgi_app(self, environ, start_response): #ctx是ResquestContext的对象,里面request,session ctx = self.request_context(environ) error = None try: try: #就是ctx放到了Local对象 ctx.push() #所有请求的执行函数的,包括请求扩展,真正的视图函数 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 # 请求之后的函数 return response(environ, start_response) finally: if self.should_ignore_error(error): error = None ctx.auto_pop(error)
1. ctx = self.request_context(environ) : environ,请求相关的,ctx现在是包含request,session的RequestContext的对象,源码
1.1 RequestContext(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.1 RequestContext.push()的源码 def push(self): #_request_ctx_stack是localStack的对象 #self是ctx,把self也就ctx放入到local对象里面 _request_ctx_stack.push(self) 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() 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方法 源码: #obj是ctx def push(self, obj): #obj是ctx,requestContext的对象 rv = getattr(self._local, "stack", None) if rv is None: # self._local是Local()的对象 # storage[“线程id或者协程id”][stack] = [ctx,] self._local.stack = rv = [] rv.append(obj) return rv # 最终也就是ctx.push()他的最终目的:把当前的ctx放入到Local()里面
3. response = self.full_dispatch_request() 源码:
def full_dispatch_request(self): #这是服务器第一次请求时候执行的函数 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
4. 我们的现在已经在2步的时候把我们request已经方法Locald对象中了,我们第三步的任意一个地方都能使用我们的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.3 我们来看这个_request_ctx_stack.top的top方法 def top(self): try: return self._local.stack[-1] except (AttributeError, IndexError): return None # 我们发现这个self._local是Local()对象,这样就把ctx拿到了
原文:https://www.cnblogs.com/lovershowtime/p/11750174.html