flask源码(2)__The actual WSGI application——wsgi_app

前景

上一次我梳理了下,一个app最基本的流程,今天来看一下WSGI是如何去处理请求的

WSGI请求处理

上一部分的WSGIRequestHandler虽然是作为request的处理,但是实际上处理的并不是它而是调用的app()这个函数,传递给它environ和start_response,我们进app.py这个文件一探究竟

__call__

    def __call__(self, environ, start_response):
        """Shortcut for :attr:`wsgi_app`."""
        return self.wsgi_app(environ, start_response)

源码最后写了一个call方法,将自己作为函数可被调用,最后调用wsgi_app这个方法

wsgi_app

    def wsgi_app(self, environ, start_response):
        # 创建请求的上下文,并把它push压入栈
        ctx = self.request_context(environ)
        ctx.push()
        error = None
        try:
            try:
                # 处理http请求的业务逻辑,分发请求到视图函数上
                response = self.full_dispatch_request()
            # 异常处理
            except Exception as e:
                error = e
                response = self.handle_exception(e)
            except:
                error = sys.exc_info()[1]
                raise
            return response(environ, start_response)
        finally:
            if self.should_ignore_error(error):
                error = None
            # 不管处理是否发生异常,将栈中的请求pop出来
            ctx.auto_pop(error)

full_dispatch_request

    def full_dispatch_request(self):
        """
        分发请求,并且在这之前进行请求预处理和后处理并且处理HTTP异常和错误
        """
        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)

try_trigger_full_dispatch_request_functions
处理flask中berfore_first_request的

    def try_trigger_before_first_request_functions(self):
        # 在每次request时调用,保证能触发before_request_funcs,并且对于一个实例只能触发一次
        # 实际上就是是否是第一个请求,第一次请求前,self._got_first_request = False,
        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()
            # 执行完毕之后,会改为True,表示不再是第一次了
            self._got_first_request = True

接下来是预处理 * preprocess_request()*:预处理函数,处理的是被before_request装饰的函数。也就是在每个请求之前会被调用的一个函数,flask中的钩子函数就是这么处理的

    def preprocess_request(self):
    """
    在真实请求分发前调用,会调用before_request装饰的函数,不传递参数。
    如果其中任何一个函数返回了值,那么就把这个值当成了视图函数的返回,后续的请求处理将会停止。
    这也会触发url_value_preprocessor函数,在before_request函数之前调用
    """
        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

解读:
  其实就是触发url_value_preprocessor,和before_request之后才会执行这个函数。因为它先从这两个里面get,获取,如果有才执行。默认里面self.url_value_preprocessors = {} 和self.before_request_funcs = {},这两个都是空的,所以我们暂时可以先不看

总结作用:就是两个函数的预处理,触发了就执行,没有就不执行

rv = self.dispatch_request()

    def dispatch_request(self):
        """
        执行request的分发,匹配URL返回视图函数的值,不必成为一个response对象,可以调用make_response,转变返回值使之成为一个response
        """
        # 从栈中读取request,而不是通过参数
        req = _request_ctx_stack.top.request
        if req.routing_exception is not None:
            self.raise_routing_exception(req)
        rule = req.url_rule
        # 如果提供了automatic 选项给URL并且,request来自options方法,自动回复
        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)

解读一下:

我们可以看到,这个函数最终返回的是一个url endpoint(‘/’,’/index’)之类的和视图函数的映射字典 self.view_functions = {},

request最终处理:finalize_request

    def finalize_request(self, rv, from_error_handler=False):
        """
        因为已经从视图函数中得到了返回值,所以最终将request打包成一个response
        """
        # make_response,将视图函数中的返回值打包成为一个真正的response对象
        response = self.make_response(rv)
        try:
            # process_response()是一个after_resuqest处理函数,在有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

总结作用:
这个函数就是给WSGIRequestHandler,也就是给WSGI服务器返回最终response的函数,到这里一个完整的WSGI的request处理就结束了,至于怎么make_response那是app的事情。

总结

真实的WSGI应用实际上是在app中的,WSGIRequestHandler把环境和start_response传给app,然后app里面的wsgi_app来把request分发到视图上的。然后最后进行response的打包。WSGI真正的流程是这个样子。终于搞清楚简单的流程了-。-明天去看看上下文的处理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

河海哥yyds

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值