Flask快速入门(11) — 请求流程
目录
flask项目整个请求流程其实就是执行:wsgi_app()方法中调用的full_dispatch_request(),包括请求扩展和真正的视图函数
full_dispatch_request()
def full_dispatch_request(self):
# 执行before_first_request函数
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)
在分析这段代码之前,先回顾下请求扩展函数
(1)@app.before_first_request:就是将第一次请求之前的函数刚入self.before_first_request_funcs列表中
def before_first_request(self, f):
self.before_first_request_funcs.append(f)
return f
(2)@before_request:将请求之前函数放入self.before_request_funcs列表中
def before_request(self, f):
self.before_request_funcs.setdefault(None, []).append(f)
return f
(3)@after_request:将请求之后函数放在self.after_request_funcs列表中
def after_request(self, f):
self.after_request_funcs.setdefault(None, []).append(f)
return f
1. try_trigger_before_first_request_functions():第一次请求之前
def try_trigger_before_first_request_functions(self):
if self._got_first_request: # 初始为False
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
将self.before_first_request_funcs也就是第一次请求前函数一个个取出执行。执行完后将self._got_first_request设为True。这样在后面的请求中就不再执行,也就是说只在第一次请求之前执行
2. self.preprocess_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 rv
3. self.dispatch_request():请求
def dispatch_request(self):
req = _request_ctx_stack.top.request
if req.routing_exception is not None:
self.raise_routing_exception(req)
rule = req.url_rule
if (
getattr(rule, "provide_automatic_options", False)
and req.method == "OPTIONS"
):
return self.make_default_options_response()
# 执行真正的视图函数
return self.view_functions[rule.endpoint](**req.view_args)
4. finalize_request():请求之后
def finalize_request(self, rv, from_error_handler=False):
# 先make_response响应
response = self.make_response(rv)
try:
# 执行请求之后函数
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
def process_response(self, response):
ctx = _request_ctx_stack.top
bp = ctx.request.blueprin
funcs = ctx._after_request_functions
# reversed将请求之后函数列表进行了反转
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,所以我们的请求之后函数必须要有个参数。并且要有返回值
response = handler(response)
if not self.session_interface.is_null_session(ctx.session):
self.session_interface.save_session(self, ctx.session, response)
return response
以上就是请求相关的流程。总结:
- 先执行第一次请求之前函数,执行完之后后续请求中不再执行
- 再从上往下执行请求之前函数,如果有返回值,不再执行后面的请求之前函数,也不执行真正的视图函数
- 没有返回值时执行视图函数,再执行请求之后函数
- 请求之后函数必须要有参数,并且有返回值
- 请求之后函数是从下往上返回执行