目录
之前分析了flask项目从启动到请求结束实际是执行了wsgi_app函数,在“请求流程”中也分析了self.full_dispatch_request()
是执行了请求的视图函数以及请求扩展。现在分析其它源码:
def wsgi_app(self, environ, start_response):
ctx = self.request_context(environ)
error = None
try:
try:
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)
def request_context(self, environ):
return RequestContext(self, 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._implicit_app_ctx_stack = []
self.preserved = False
self._preserved_exc = None
self._after_request_functions = []
ctx 就是RequestContext的一个对象,封装了一些参数,包括处理后的request、session...
2. ctx.push()
ctx是RequestContext对象,实际是执行了RequestContext的push方法,在push方法里主要看执行了_request_ctx_stack.push(self)
方法
def push(self):
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)
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 _request_ctx_stack是什么?
_request_ctx_stack
是LocalSrack()的对象,也就是说_request_ctx_stack.push(self)
执行的是LocalSrack的push方法,self就是ctx(请求相关的)
def push(self, obj):
# 从self._local获取"stack"值,若为None,就设为空列表[];否则将obj即ctx放入“stack”的列表中去
rv = getattr(self._local, "stack", None)
if rv is None:
self._local.stack = rv = []
rv.append(obj)
return rv
self._local
就是local对象。local中没有stack属性,所以执行local的__getattr__()
方法。这就是flask上篇介绍到的local对象。通过线程id或协程id来开辟不同的存储空间,放入request、session等相关的信息。这样就可以实现多线程或多协程
3. response = self.full_dispatch_request()
请看“请求流程“篇,这里不再重复介绍
4. ctx.auto_pop(error)
def auto_pop(self, exc):
if self.request.environ.get("flask._preserve_context") or (
exc is not None and self.app.preserve_context_on_exception
):
self.preserved = True
self._preserved_exc = exc
else:
self.pop(exc) # self是ctx,所以执行的是RequestContext的pop方法
def pop(self, exc=_sentinel):
app_ctx = self._implicit_app_ctx_stack.pop() # self._implicit_app_ctx_stack = []
try:
clear_request = False
if not self._implicit_app_ctx_stack:
self.preserved = False
self._preserved_exc = None
if exc is _sentinel:
exc = sys.exc_info()[1]
self.app.do_teardown_request(exc)
if hasattr(sys, "exc_clear"):
sys.exc_clear()
request_close = getattr(self.request, "close", None) # 如果有request.close就执行request_close()方法
if request_close is not None:
request_close()
clear_request = True
finally:
rv = _request_ctx_stack.pop() # 主要是执行了这句
if clear_request:
rv.request.environ["werkzeug.request"] = None
if app_ctx is not None:
app_ctx.pop(exc)
assert rv is self, "Popped wrong request context. (%r instead of %r)" % (rv,self,)
4.1 rv =_request_ctx_stack.pop()
刚刚提到过_request_ctx_stack是LocalStack对象,所以执行的是LocalStack的pop方法
def pop(self):
# self._local是Local对象,获取stack属性值,如果有就return stack[-1]
stack = getattr(self._local, "stack", None)
if stack is None:
return None
elif len(stack) == 1:
release_local(self._local)
return stack[-1]
else:
return stack.pop()
总结:在该请求执行完之后pop掉ctx请求