目录
Flask请求上下文源码分析
from flask import Flask
app = Flask(__name__)
if __name__ == '__main__':
app.run()
分析入口app.run(),点入查看源码:
from werkzeug.serving import run_simple
try:
run_simple(host, port, self, **options)
#这里的self是app自己
run_simple是werkzeug内部的方法,在run_simple执行时会将app加括号调用从而执行app的__call__方法,来看__call__源码:
def __call__(self, environ, start_response):
"""The WSGI server calls the Flask application object as the
WSGI application. This calls :meth:`wsgi_app` which can be
wrapped to applying middleware."""
return self.wsgi_app(environ, start_response)
进入wsgi_app:
ctx就是RequestContext对象,请求上下文对象ctx中初始化所有请求所有内容,并且其内部封装着Request对象,Request对象把请求过来的信息格式化并且储存起来。
1 ctx = self.request_context(environ)---》ctx本质是RequestContext的对象
1.1 RequestContext(self, environ) :self是当前的app,environ是请求相关的
1.2 RequestContext(self, environ)执行的结果是:RequestContext类的对象,该对象中包含了请求相关和当前的app
1.3 所以这个ctx就是RequestContext的对象。
'''
environ:A WSGI environment
start_response: A callable accepting a status code,a list of headers, and an optional exception context to start the response.
'''
def wsgi_app(self, environ, start_response):
ctx = self.request_context(environ)
#在self.request_context(environ)中
#RequestContext类中的 `__init__`实例化出请求上下文对象ctx
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)
2 ctx.push():当前ctx是RequestContext的对象,那就是执行RequestContext的对象的push方法
2.1 ctx.push方法中有一个 _request_ctx_stack.push(self);这个self是ctx, 那就是把ctx,传递给_request_ctx_stack
2.2 _request_ctx_stack是什么?--》 LocalStack的对象
2.3 _request_ctx_stack.push方法是什么?看源码:
obj就是_request_ctx_stack.push(self),传过来的self,也就是ctx
def push(self, obj):
rv = getattr(self._local, "stack", None)
if rv is None:
#storage["线程或者协程的id"][stack] = []
self._local.stack = rv = []
# storage["线程或者协程的id"][stack] = [ctx,]
rv.append(obj)
return rv
2.3.1 在2.3的代码中self._local.stack做了什么?
我们发先self._local是Local对象,所以self._local就执行
Local对象的__setattr__:代码如下:
def __setattr__(self, name, value):
ident = self.__ident_func__()
storage = self.__storage__
try:
#name = stack
storage[ident][name] = value
except KeyError:
storage[ident] = {name: value}
对2的总结:就是将ctx放到Locl对象中以这样的形式存储storage[ident][stack] = [ctx,]
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 self.try_trigger_before_first_request_functions()
:这是在执行请求扩展中的befor_first_request
它是如何判断项目启动后只执行里面方法一次的呢?
答:它是通过self._got_first_request
变量来判断的,初始值为False,一旦执行过该函数,在函数的末尾self._got_first_request
设置成True
源码如下:
def try_trigger_before_first_request_functions(self):
if self._got_first_request:
return
with self._before_request_lock:
if self._got_first_request:
return
#这里去循环第一次执行的函数,请求扩展的里面
for func in self.before_first_request_funcs:
func()
self._got_first_request = True
3.2 rv = self.preprocess_request()
这里执行的是befor_request
的函数,
源码如下:
def preprocess_request(self):
bp = _request_ctx_stack.top.request.blueprint
funcs = self.url_value_preprocessors.get(None, ())
if bp is not None and bp in self.url_value_preprocessors:
funcs = chain(funcs, self.url_value_preprocessors[bp])
for func in funcs:
func(request.endpoint, request.view_args)
#请求之前的要做的事情,请求之前的请求扩展
funcs = self.before_request_funcs.get(None, ())
if bp is not None and bp in self.before_request_funcs:
funcs = chain(funcs, self.before_request_funcs[bp])
for func in funcs:
rv = func()
if rv is not None:
return r
3.2.1 funcs = self.before_request_funcs.get(None, ())
这里是获取所有注册进来的befor_request
3.2.2 下面的代码可以看出:如果befor_before_request
函数有一个有返回值,那后面的函数都不执行,并且把返回值给rv = self.preprocess_request()
的rv
for func in funcs:
rv = func()
if rv is not None:
return rv
3.3 if rv is None
: 这个rv是3.2中befor_reuqest
返回的,如果没有返回值才会执行rv = self.dispatch_request()
;有返回值不会执行rv = self.dispatch_request()
这是真正的响应函数
通过这个代码:我们知道,如果befor_request
有返回值,就不会执行真正的响应函数
3.4 return self.finalize_request(rv)
:这个个rv是3.2或者3.3的返回值
源码如下:
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
3.4.1 response = self.process_response(response)
:这里做after_request
请求扩展的
源码如下:
def process_response(self, response):
ctx = _request_ctx_stack.top
bp = ctx.request.blueprint
funcs = ctx._after_request_functions
if bp is not None and bp in self.after_request_funcs:
funcs = chain(funcs, reversed(self.after_request_funcs[bp]))
if None in self.after_request_funcs:
funcs = chain(funcs, reversed(self.after_request_funcs[None]))
for handler in funcs:
response = handler(response)
if not self.session_interface.is_null_session(ctx.session):
self.session_interface.save_session(self, ctx.session, response)
return response
在上述代码中有两行代码:if None in self.after_request_funcs
:
funcs是所有after_request的函数列表,并用reversed做了反转
这个我们就知道,在after_request为什么先注册的后执行funcs = chain(funcs, reversed(self.after_request_funcs[None]))
for handler in funcs:
在这里知道after_request的函数必须接收这个response,并且要做返回response = handler(response)
4 我们知道3中就可以调用request属性了,那它怎么做到呢?当我们在3中的任意一个位置,都能调用request或者其他的。比如我们request.methons,
它是如果找到当前请求的request呢
4.1 当我们调用request.methons
的时候,我们先要看看rquest是什么?
看源码我们知道:request = LocalProxy(partial(_lookup_req_object, "request"))
也就说是LocalProxy对象
4.2 当我们调用request.methons就会返回属性methons属性给我们,但是我们在LocalProxy根本就没有methons属性,那我们想到,既然没有这个属性,那一定会走__getattr__
LocalProxy的__getattr__
源码如下:
def __getattr__(self, name):
if name == "__members__":
return dir(self._get_current_object())
return getattr(self._get_current_object(), name)
上述代码中name,就是我们要找的methons属性,那它是从self._get_current_object()
通过反射那拿去的,从下面的分析中我们知道self._get_current_object()
就是request。
4.2.1 self._get_current_object()的返回值是什么?通过下面的源码我们可以看到就self.__local()执行结果
源码:
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__)
4.2.1.1 self.__local()
的执行结果是什么?我们先搞清楚self.__local
是什么?
我们发现self.__local
是通过如下初始化得到的:
def __init__(self, local, name=None):
object.__setattr__(self, "_LocalProxy__local", local)
那我们可以知道self.__local就是4.1 中 LocalProxy(partial(_lookup_req_object, "request"))
的参数,
也就 partial(_lookup_req_object, "request")
偏函数
4.2.1.2 我们现在知道self.__local
是 partial(_lookup_req_object, "request")
那 self.__local()
就是 partial(_lookup_req_object, "request")()
执行
4.2.1.3 partial(_lookup_req_objec,"request")
相当于给_lookup_req_objec
函数传递了一个"request"
参数
_lookup_req_objec
的源码如下:
#name 为 "request"
def _lookup_req_object(name):
#到Local中取取ctx取出来了
top = _request_ctx_stack.top
#top就是ctx
if top is None:
raise RuntimeError(_request_ctx_err_msg)
#cxt中取request,把request返回回去了
return getattr(top, name)
我们从 4.2.1.3.1得知:top就是ctx,getattr(top, name)
就是从ctx中找request,并且返回那4.2.1.2中self.__local
执行的结果就是request
4.2.1.3.1 上述代码中_request_ctx_stack.top
的源码如下:
@property
def top(self):
try:
#返回了一开始进去的ctx对象
return self._local.stack[-1]
except (AttributeError, IndexError):
return None
self._local也是Local对象.stack就是在执行__getattr__
代码如下:
def __getattr__(self, name):
try:
return self.__storage__[self.__ident_func__()][name]
except KeyError:
raise AttributeError(name)
这样_request_ctx_stack.top
的到的结果就ctx,那 4.2.1.3 中的 top = _request_ctx_stack.top;top就是ctx