每篇前言:
🏆🏆作者介绍:【孤寒者】—CSDN全栈领域优质创作者、HDZ核心组成员、华为云享专家Python全栈领域博主、CSDN原力计划作者
- 🔥🔥本文已收录于Flask框架从入门到实战专栏:《Flask框架从入门到实战》
- 🔥🔥热门专栏推荐:《Python全栈系列教程》、《Django框架从入门到实战》、《爬虫从入门到精通系列教程》、《前端系列教程》、《tornado一条龙+一个完整版项目》。
- 📝📝本专栏面向广大程序猿,为的是大家都做到Flask从入门到精通,穿插有很多实战优化点。
- 🎉🎉订阅专栏后可私聊进一千多人Python全栈交流群(手把手教学,问题解答); 进群可领取Python全栈教程视频 + 多得数不过来的计算机书籍:基础、Web、爬虫、数据分析、可视化、机器学习、深度学习、人工智能、算法、面试题等。
- 🚀🚀加入我一起学习进步,一个人可以走的很快,一群人才能走的更远!
经过上文分析,我们可以将整个过程分为三阶段:
-
将ctx对象(包含request和session)放到Local对象中;
-
视图函数导入:request/session;
-
请求处理完毕:
- 获取session并加密后保存到cookie
- 将ctx删掉
第一阶段:
将ctx对象(包含request和session)放到Local对象中。
进去(下图中self就是ctx对象!):
继续进:
显而易见,上述_request_ctx_stack
是一个全局变量,在整个应用程序的生命周期中它只创建一次!这是一种单例模式的实现方式~
继续进:
可以看到这个对象里又包了一个对象,这个_local
对象才是真正存ctx的!而上面的_request_ctx_stack
对象则相当于是一个代理,每次需要存ctx的时候都要先交给代理,代理再将其给到真正存储ctx的_local
对象里!
上述push方法中_local
对象点stack又会触发Local对象的__setattr__
方法:
下图以第一阶段为主画了个简单的流程图,以便大家更好地梳理!
拓展一:flask里的session 是什么时候创建,什么时候销毁的?
当请求刚进来的时候,会将request和session封装成一个request_context
对象,接下来通过LocalStack把这个对象放到内部的Local
里【注意:现在session还是空的!】
下一步,执行open_session
,将cookie里的值拿来处理后再放到Local
中的ctx里。
最后,返回的时候要执行save_session
将ctx里的session读出来序列化后存到用户cookie中,再将ctx给pop掉~
第二阶段:
分析下图的流程:
from flask import Flask, request
app = Flask(__name__)
@app.route('/')
def hello_world():
print(request) # 执行request对象的__str__方法
request.method # 执行request对象的__getattr__(key='method')方法
return 'hello world~'
if __name__ == '__main__':
app.__call__
app.run()
看源码,进request:
回去:
from flask import Flask, request
app = Flask(__name__)
@app.route('/')
def hello_world():
print(request) # LocalProxy对象的__str__
request.method # LocalProxy对象的__getattr__(key='method') 这一步应该包含多个操作:先去ctx中拿到request,再去request中获取method
return 'hello world~'
if __name__ == '__main__':
app.__call__
app.run()
进LocalProxy源码:
进去_get_current_object()
:
__local
就是最开始传给LocalProxy的经过偏函数处理的那个函数,下图中的这个:
__local
函数加括号执行这个函数,进去看:
继续看session:
如上图所指会执行session对象的__setitem__
方法~
进session源码:
和request区别就是传的参数是session:
跳出来:
from flask import Flask, request, session
app = Flask(__name__)
@app.route('/')
def hello_world():
print(request) # LocalProxy对象的__str__
request.method # LocalProxy对象的__getattr__ 这一步应该包含多个操作:先去ctx中拿到request,再去request中获取method
session['k1'] = 'guhanzhe' # LocalProxy对象的__setitem__(key=k1, value='guhanzhe') # 先去ctx中拿到session,再给session中设置对应的值
session['k1'] # LocalProxy对象的__getitem__(key='1') # 先去ctx中拿到session,再去session中获取对应的值
return 'hello world~'
if __name__ == '__main__':
app.__call__
app.run()
视图函数中有关于request和session的操作都是通过LocalProxy对象这个中介操作,然后再通过函数_lookup_req_object
去ctx获取到request和session对象。
第三阶段:
pop肯定也不是直接pop的,也要走中介,如下图蓝色流程线:
但是上述所画几个流程图其实都不全,所以再来缕一遍源码:
进push:
在这个AppContext对象中,又封装了两个值:app和g!
回退:
封装了那两个值后执行app_ctx.push()
,再来看看app_ctx
是啥?
所以流程图又要更新了!这次多了个存放app(就是程序进来实例化的Flask对象)和g的对象!!!
完整画图:
上面刚说多了个g和app:
进去g:
进去current_app:
是不是和request和session一个流程!!!
最后来看看最后的最后:
把最后的最后补充进图:
上面这个机制支持多线程!
Flask中一共有几个LocalStack和Local对象?
- 都是两个~