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

以上就是请求相关的流程。总结:

  • 先执行第一次请求之前函数,执行完之后后续请求中不再执行
  • 再从上往下执行请求之前函数,如果有返回值,不再执行后面的请求之前函数,也不执行真正的视图函数
  • 没有返回值时执行视图函数,再执行请求之后函数
  • 请求之后函数必须要有参数,并且有返回值
  • 请求之后函数是从下往上返回执行
posted @ 2019-10-16 19:18  Never&say&die  阅读(1075)  评论(0编辑  收藏  举报