• 请求上下文源码分析


    flask项目一启动,有6个全局变量

    _request_ctx_stack:LocalStack #LocalStack对象
    _app_ctx_stack:LocalStack #LocalStack对象
    current_app:LocalProxy(_find_app)
    request:LocalProxy #LocalStack对象
    session:LocalProxy #LocalStack对象
    g:LocalProxy #LocalStack对象
    

    请求来了

    app.__call__()----->内部执行:self.wsgi_app(environ, start_response)

    wsgi_app()

    1.执行:ctx = self.request_context(environ):返回一个RequestContext对象,并且封装了request(当次请求的request对象),session。
    2.执行:ctx.push():RequestContext对象的push方法
        2.1 push方法中中间位置382行有:_request_ctx_stack.push(self),self指的是ctx对象
        2.2 去_request_ctx_stack对象的类中找push方法(LocalStack中找push方法)
        2.3 push源码
    
    def push(self, obj):
        # 通过反射找到self._local,在__init__实例化的时候生成的:self._local = Local()
        # Local() flask封装了支持线程和协程的local对象
        # 一开始取不到stack,返回None
        rv = getattr(self._local, "stack", None)
        if rv is None:
            # 走到这,self._local.stack = [],rv = []
            self._local.stack = rv = []
            # 把ctx放到列表中
            # self._local={'线程id1':{'stack':[ctx,]},'线程id2':{'stack':[ctx,]},'线程id3':{'stack':[ctx,]}}
        rv.append(obj)
        return rv
    

    如果在视图函数中使用request对象,比如:print(request)

    1.会调用request对象的`__str__`方法,request类是:LocalProxy
    2.LocalProxy中的`__str__`方法:lambda x: str(x._get_current_object())
        1.内部执行_get_current_object()方法的源码如下:
    
        def _get_current_object(self):
            if not hasattr(self.__local, "__release_local__"):
            # self.__local()在__init__的时候,实例化的,在__init__中:object.__setattr__(self, "_LocalProxy__local", local)
            # 用了隐藏属性
            # self.__loacl
                # 实例化该类的时候传入的local(偏函数的内存地址:request = LocalProxy(partial(_lookup_req_object, "request")))
                # 加括号返回,就会执行偏函数,也就是执行_lookup_req_object,不需要传参数了
                # 这个地方的返回值就是request对象(当次请求的request,没有乱)
                return self.__local()
            try:
                return getattr(self.__local, self.__name__)
            except AttributeError:
                raise RuntimeError("no object bound to %s" % self.__name__)
    
        3._lookup_req_object函数源码如下:
    
    def _lookup_req_object(name):
        # name就是'request'字符串
        # top方法是把第二步中放入的ctx取出来,因为都在一个线程内,当前取到的就是当前请求的ctx对象
        top = _request_ctx_stack.top
        if top is None:
            raise RuntimeError(_request_ctx_err_msg)
        # 通过反射,去ctx中把request对象返回
        return getattr(top, name)
    
        4.所以:print(request)实质上是在打印当次请求的request对象的__str__
    

    如果在视图函数中使用request对象

    比如:print(request.method):实质上是取到当次请求的request对象的methid属性
    

    最终,请求结束执行

    ctx.auto_pop(error)# 把ctx移除掉
    
  • 相关阅读:
    NOIP2014D2T2寻找道路(Spfa)
    【割点】【割边】tarjan
    NOIP2013D1T3货车运输(最大生成树+倍增lca)
    lca最近公共祖先(模板)
    人生第一次hash
    【模板】Tarjan求强连通分量
    【模板】链式前向星+spfa
    二叉树的三种遍历
    hdu 3549 最大流
    hdu 1532&&poj1273 基础最大流
  • 原文地址:https://www.cnblogs.com/ShenJunHui6/p/11219573.html
Copyright © 2020-2023  润新知