源码:
1. 全局的变量
_request_ctx_stack = LocalStack()
_app_ctx_stack = LocalStack()
current_app = LocalProxy(_find_app)
request = LocalProxy(partial(_lookup_req_object, "request"))
session = LocalProxy(partial(_lookup_req_object, "session"))
g = LocalProxy(partial(_lookup_app_object, "g"))
2. flask请求上下文全部与源码:
def wsgi_app(self, environ, start_response):
#environ请求相关的所有数据,ctx就是ResquestContext的对象,包含request
ctx = self.request_context(environ)
error = None
try:
try:
#把request放进去了,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
##把request,和session删除
ctx.auto_pop(error)
2.1 ctx = self.request_context(environ),这个environ是请求相关的
self.request_context(environ)这个话的本质是执行return RequestContext(self, environ)
现在传给RequestContext的变量self是当前app,environ是请求相关的
2.1.1我们发现RequestContext是一个类,类加括号是就实例化得到对象,
这个对象里面有request,session等:
app-->就当前的flask对象,environ请求相关的
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.preserved = False
self._preserved_exc = None
self._after_request_functions = []
2.1.2 这样我们执行ctx = self.request_context(environ),
得到是RequestContext的对象这个对象里面有request,session等,
2.2 ctx.push()的源码:
执行的是RequestContext里面的push方法: _request_ctx_stack.push(self),当前的self是ctx
我们发现_request_ctx_stack就是LocalStack() ,
_request_ctx_stack.push(self)就是执行LocalStack的push,并且把ctx传过来了
2.2.1 _request_ctx_stack.push(self)的源码:
#obj就是ctx,self._local是Local对象,用来区分不同线程,协程的数据
def push(self, obj):
rv = getattr(self._local, "stack", None)
if rv is None:
# self._local=>stack-->storage['线程id']['stack']=[]
self._local.stack = rv = []
# self._local=>stack-->storage['线程id']['stack']=[ctx,]
rv.append(obj)
return rv
3. request是怎样取到我放到 Local对象里面的ctx在里面的request
request = LocalProxy(partial(_lookup_req_object, "request"))
当我们request.form时候就会找LocalProxy(partial(_lookup_req_object, "request"))要form属性
3.1当要request属性时候,就会执行LocalProxy的getattr,源码:
#name=我们要的属性,比如request.form的form,name=form
def __getattr__(self, name):
if name == "__members__":
return dir(self._get_current_object())
#name-->form,self._get_current_object()===>ctx.request,form
return getattr(self._get_current_object(), name)
最后我们发现self._get_current_object()是我们在实例化
LocalProxy(partial(_lookup_req_object, "request"))
传过来的偏函数执行结果。
3.1.1:self._get_current_object()要执行的代码是:
def _get_current_object(self):
if not hasattr(self.__local, "__release_local__"):
return self.__local()
try:
return getattr(self.__local, self.__name__)
except AttributeError:
raise RuntimeError("no object bound to %s" % self.__name__)
3.1.1.1 self._get_current_object()这个里面的self.__local():
我们发先这个self.__local是在实例化的时候传过来:
def __init__(self, local, name=None):
object.__setattr__(self, "_LocalProxy__local", local)
我们发现传过来的是partial(_lookup_req_object, "request")偏函数:
偏函数源码:
#name=request
def _lookup_req_object(name):
top = _request_ctx_stack.top
#top就是我们前面放进去ctx
if top is None:
raise RuntimeError(_request_ctx_err_msg)
#getattr(top, name)的意思就是到ctx里面找request
return getattr(top, name)
3.1.1.1.1 top = _request_ctx_stack.top: # _request_ctx_stack是 LocalStack()的对象:
源码:
@property
def top(self):
try:
#返回ctx
return self._local.stack[-1]
except (AttributeError, IndexError):
return None