table of Contents
Before analyzing the flask project from start to end of the request is actually executed wsgi_app function in the "request process," also analyzed self.full_dispatch_request()
the implementation of the view function request and request extensions. Now analyze other Source:
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 is an object that encapsulates some of the parameters, including the processing request, session ...
2. ctx.push()
ctx is RequestContext object is actually executed push method RequestContext, mainly to see the push method in the implementation of the _request_ctx_stack.push(self)
method
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()
What 2.1 _request_ctx_stack that?
_request_ctx_stack
It is LocalSrack () object, which means that _request_ctx_stack.push(self)
the implementation of the push method LocalSrack, self is ctx (request related)
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
It is the local object. No local stack attribute, the local execution of __getattr__()
the method. This is the introduction to Part flask of local objects. To open up different storage space by a thread or coroutine id id, into related information request, session and so on. This enables multi-threaded or multi-coroutines
3. response = self.full_dispatch_request()
See "request process" articles, will not be repeated here Introduction
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()
Just mentioned _request_ctx_stack is LocalStack object, so that the execution of the pop method LocalStack
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()
Summary: After the request is executing the pop out ctx request