上下文管理的几个阶段

flask的上下文管理 随笔 第1张
第一阶段:将ctx(request,session)放到“空调”上(Local对象)
           
第二阶段:视图函数导入:request/session 

第三阶段:请求处理完毕
                - 获取session并保存到cookie
                - 将ctx删除
flask的上下文管理 随笔 第2张

源码分析

首先当请求来时,我们会执行app.run方法,这个方法其实执行的是run_simple方法,而run_simple实际上执行的是app()

一个对象加括号执行的是__call__方法

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

flask的上下文管理 随笔 第3张

这里的__call__实际上执行的是self.wsgi_app

flask的上下文管理 随笔 第4张

在这个方法中首先定义了一个ctx,这是一个什么呢,我们来看看self.request_context(environ)

flask的上下文管理 随笔 第5张

可以看到self.request_context(environ)返回的是一RequestContext类的对象,所以ctx是这个类的一个对象,我们再看看RequestContext类的内容

flask的上下文管理 随笔 第6张

在这个类的init方法中我们定义了request和session,其中request=app.request_class,这个app.request_class也是个类

flask的上下文管理 随笔 第7张

定义完ctx对象后我们要执行这个对象的push方法

flask的上下文管理 随笔 第8张

在这个方法中我们看到有两个参数_app_ctx_stack和_request_ctx_stack,这两个参数是什么呢

flask的上下文管理 随笔 第9张

可以看到他们都是LocalStack类的对象,并且都是flask的全局变量,也就是导入时就有的,所以在每一个请求中用到的都是同一个对象单例

flask的上下文管理 随笔 第10张

在这个类中还实例了一个Local的对象,所以_app_ctx_stack和_request_ctx_stack对象各自都有一个_local对象

flask的上下文管理 随笔 第11张

这个Local类的init方法中定义了一个__storage__的空字典,还定义了__ident_func__这个每个线程都不同的参数,这个__storage__的空字典就是用来存放每个请求过来时生成的ctx对象的,不同的请求,不同的线程通过__ident_func__区分

有了上面定义的_app_ctx_stack和_request_ctx_stack参数后,接着执行了他们的push方法

flask的上下文管理 随笔 第12张

这里首先通过getattr获取self._local的stack属性,如果没有,则进行设置self._local.stack = rv = []

而通过.设置的过程其实就是执行self._local对象的__setattr__方法

flask的上下文管理 随笔 第13张

在这个方法中根据不同的线程号,在self.__storage__字典中创建了不同的键值对,键就是每个请求线程对应的get_ident值,值为一个字典,字典的键为stark,值为包含每个请求对应的ctx对象的字典,这个ctx对象中还包含了request和session

执行完push后,又进行session操作,这里就不再讨论session操作,可以参考前面博客中关于session源码的解释,然后会执行我们的视图函数

flask的上下文管理 随笔 第14张

当然在执行视图函数之前还会执行before_request

flask的上下文管理 随笔 第15张

在视图函数中我们可以通过导入request和session等来进行使用,那么导入并使用的过程是怎样的呢,我们以request为例

flask的上下文管理 随笔 第16张

可以看到我们导入的request其实是一个LocalProxy类的对象,实例化过程中传了一个偏函数_lookup_req_object为对象,这个函数的参数为request

 flask的上下文管理 随笔 第17张

在LocalProxy类实例化时,我们执行了object.__setattr__(self, '_LocalProxy__local', local),这其实是定义了这个类的一个隐藏属性,等同于__local=local(_lookup_req_object(request))

那么这个_lookup_req_object函数都做了什么呢

flask的上下文管理 随笔 第18张

他其实是从_request_ctx_stack.top中获取name属性,这个name就是我们传的request

 flask的上下文管理 随笔 第19张

而这个top对应的其实就是我们当前线程的ctx对象,所以_lookup_req_object函数得到的就是ctx.request,也就是我们封装好的request

所以当我们执行request.method等指令时,其实执行的是LocalProxy类中的_getattr__方法

flask的上下文管理 随笔 第20张

在这个方法中我们获取到到的是self._get_current_object()的name属性,name就是我们点后面的值(如method),而self._get_current_object()是什么呢

flask的上下文管理 随笔 第21张

可以看到它返回的其实是self.__local()而我们上面提到了self.__local=_lookup_req_object函数,加括号执行就得到了我们的request对象,所以我们就得到了request对象的method方法

session和request同理,我们还注意到其实我们还可以导入current_app和g,他们都是在_app_ctx_stack对应的local中的

flask的上下文管理 随笔 第22张

current_app导入的就是当前的app对象

flask的上下文管理 随笔 第23张

而g是我们可以自己设置的,如当请求来时,我们可以先判断用户的权限,将相应的权限写入到g中,然后在视图函数中就可以直接从g中取到用户的权限了

 flask的上下文管理 随笔 第24张

执行完成视图函数后,我们接着执行后续的response操作,可以参考session的源码

最后我们要执行一个ctx.auto_pop(error)

flask的上下文管理 随笔 第25张

这个操作做了什么呢

flask的上下文管理 随笔 第26张

执行了self.pop也就是ctx.pop

flask的上下文管理 随笔 第27张

flask的上下文管理 随笔 第28张

其实就是将local字典中对应的ctx对象删除了,所以我们上面提到的除了session,其它的request,g等的生命周期其实就是一个请求的周期

 flask的上下文管理 随笔 第29张

 flask的上下文管理 随笔 第30张

 

,flask的上下文管理 随笔 第31张
第一阶段:将ctx(request,session)放到“空调”上(Local对象)
           
第二阶段:视图函数导入:request/session 

第三阶段:请求处理完毕
                - 获取session并保存到cookie
                - 将ctx删除
flask的上下文管理 随笔 第32张

源码分析

首先当请求来时,我们会执行app.run方法,这个方法其实执行的是run_simple方法,而run_simple实际上执行的是app()

一个对象加括号执行的是__call__方法

flask的上下文管理 随笔 第33张

这里的__call__实际上执行的是self.wsgi_app

flask的上下文管理 随笔 第34张

在这个方法中首先定义了一个ctx,这是一个什么呢,我们来看看self.request_context(environ)

flask的上下文管理 随笔 第35张

可以看到self.request_context(environ)返回的是一RequestContext类的对象,所以ctx是这个类的一个对象,我们再看看RequestContext类的内容

flask的上下文管理 随笔 第36张

在这个类的init方法中我们定义了request和session,其中request=app.request_class,这个app.request_class也是个类

flask的上下文管理 随笔 第37张

定义完ctx对象后我们要执行这个对象的push方法

flask的上下文管理 随笔 第38张

在这个方法中我们看到有两个参数_app_ctx_stack和_request_ctx_stack,这两个参数是什么呢

flask的上下文管理 随笔 第39张

可以看到他们都是LocalStack类的对象,并且都是flask的全局变量,也就是导入时就有的,所以在每一个请求中用到的都是同一个对象单例

flask的上下文管理 随笔 第40张

在这个类中还实例了一个Local的对象,所以_app_ctx_stack和_request_ctx_stack对象各自都有一个_local对象

flask的上下文管理 随笔 第41张

这个Local类的init方法中定义了一个__storage__的空字典,还定义了__ident_func__这个每个线程都不同的参数,这个__storage__的空字典就是用来存放每个请求过来时生成的ctx对象的,不同的请求,不同的线程通过__ident_func__区分

有了上面定义的_app_ctx_stack和_request_ctx_stack参数后,接着执行了他们的push方法

flask的上下文管理 随笔 第42张

这里首先通过getattr获取self._local的stack属性,如果没有,则进行设置self._local.stack = rv = []

而通过.设置的过程其实就是执行self._local对象的__setattr__方法

flask的上下文管理 随笔 第43张

在这个方法中根据不同的线程号,在self.__storage__字典中创建了不同的键值对,键就是每个请求线程对应的get_ident值,值为一个字典,字典的键为stark,值为包含每个请求对应的ctx对象的字典,这个ctx对象中还包含了request和session

执行完push后,又进行session操作,这里就不再讨论session操作,可以参考前面博客中关于session源码的解释,然后会执行我们的视图函数

flask的上下文管理 随笔 第44张

当然在执行视图函数之前还会执行before_request

flask的上下文管理 随笔 第45张

在视图函数中我们可以通过导入request和session等来进行使用,那么导入并使用的过程是怎样的呢,我们以request为例

flask的上下文管理 随笔 第46张

可以看到我们导入的request其实是一个LocalProxy类的对象,实例化过程中传了一个偏函数_lookup_req_object为对象,这个函数的参数为request

 flask的上下文管理 随笔 第47张

在LocalProxy类实例化时,我们执行了object.__setattr__(self, '_LocalProxy__local', local),这其实是定义了这个类的一个隐藏属性,等同于__local=local(_lookup_req_object(request))

那么这个_lookup_req_object函数都做了什么呢

flask的上下文管理 随笔 第48张

他其实是从_request_ctx_stack.top中获取name属性,这个name就是我们传的request

 flask的上下文管理 随笔 第49张

而这个top对应的其实就是我们当前线程的ctx对象,所以_lookup_req_object函数得到的就是ctx.request,也就是我们封装好的request

所以当我们执行request.method等指令时,其实执行的是LocalProxy类中的_getattr__方法

flask的上下文管理 随笔 第50张

在这个方法中我们获取到到的是self._get_current_object()的name属性,name就是我们点后面的值(如method),而self._get_current_object()是什么呢

flask的上下文管理 随笔 第51张

可以看到它返回的其实是self.__local()而我们上面提到了self.__local=_lookup_req_object函数,加括号执行就得到了我们的request对象,所以我们就得到了request对象的method方法

session和request同理,我们还注意到其实我们还可以导入current_app和g,他们都是在_app_ctx_stack对应的local中的

flask的上下文管理 随笔 第52张

current_app导入的就是当前的app对象

flask的上下文管理 随笔 第53张

而g是我们可以自己设置的,如当请求来时,我们可以先判断用户的权限,将相应的权限写入到g中,然后在视图函数中就可以直接从g中取到用户的权限了

 flask的上下文管理 随笔 第54张

执行完成视图函数后,我们接着执行后续的response操作,可以参考session的源码

最后我们要执行一个ctx.auto_pop(error)

flask的上下文管理 随笔 第55张

这个操作做了什么呢

flask的上下文管理 随笔 第56张

执行了self.pop也就是ctx.pop

flask的上下文管理 随笔 第57张

flask的上下文管理 随笔 第58张

其实就是将local字典中对应的ctx对象删除了,所以我们上面提到的除了session,其它的request,g等的生命周期其实就是一个请求的周期

 flask的上下文管理 随笔 第59张

 flask的上下文管理 随笔 第60张

 

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄