Flask框架 之 session请求流程及源码解析
Falsk框架session请求流程
from flask import Flask
# 1. 实例化Flask对象
app = Flask(__name__)
# 2. 设置路由
"""
app.url_map = [
('/index',index),
('/login',login),
]
"""
@app.route('/index')
def index():
return "index"
if __name__ == '__main__':
# 3. 启动socket服务端
app.run()
# 4. 用户请求到来
app.__call__
app.wsgi_app
app.request_class
app.session_interface
请求到来
当请求到来,执行__call__方法。看一下源码。
def __call__(self, environ, start_response):
"""The WSGI server calls the Flask application object as the
WSGI application. This calls :meth:`wsgi_app` which can be
wrapped to applying middleware."""
#environ: 请求相关的所有数据(wsgi做了初步封装)
#start_response:用于设置响应相关的所有数据。
return self.wsgi_app(environ, start_response)
environ: 请求相关的所有数据,wsgi将原生的请求做第一步处理,把字符串分割。(wsgi做了初步封装)
start_response:用于设置响应相关的所有数据。
我们看到了一个新的函数。wsgi_app().点进去看一下。
def wsgi_app(self, environ, start_response):
'''
1、获取environ并对其进行再次封装。就成了我们要的request.
2、从environ获取名称为session的cookie值,解密,反序列化成字典
3、两个东西放到“某个神奇”的地方。
'''
ctx = self.request_context(environ)
error = None
try:
try:
ctx.push()
# 4、执行视图函数
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
'''
5、“某个神奇”的地方获取session,加密,序列化,写入cookie
6、“某个神奇”的地方位置清空 (请求结束)
'''
ctx.auto_pop(error)
小总结:
1、获取environ并对其进行再次封装。就成了我们要的request.
2、从environ获取名称为session的cookie值,解密,反序列化成字典
3、两个东西放到“神奇”的地方。
4、执行视图函数
5、“某个神奇”的地方获取session,加密,序列化,写入cookie
6、“某个神奇”的地方位置清空
request_context是什么?点进去看一下。

说明了一个问题:

RequestContext把我们的对象和请求封装到了一个类。我们对这个类进行实例化,看一下做了什么事?

我们没传request,但是传了environ.
如果request_class是一个类,那就是又进行了一次实例化。实例化之后得到一个对象request。
request = app.request_class(environ)是不是对请求在做封装,那request_class是啥?我们来看一下。发现点不进去。
在py文件写一句app.request_class,点进去。

是一个request的类。
回到wsgi_app类中,我们会得到:ctx.request=Request(environ)。
environ是一个原始的请求对象,但是现在被Request包裹,就不是原始的了。我们就可以执行".args",".form",".method"等。会自动帮我们去原始的数据解析。
通过以上,我们还可以得到一句ctx.session=None.
现在ctx已经封装了两个值了,一个是请求相关的数据,一个是session,把它放到“某个神奇的地方”。
视图函数:
下面我们来看视图函数:
在ctx.push()中点进去,上面的看不懂就不管了。

我们第一次请求session为空。进入if条件语句。app全局的。看一下session_interface.
在py文件中写一句:app.session_interface

是一个对象,就相当于对象执行了open_session方法,返回给self.session,就相当于给之前的session重新赋值。
那这个open_session是干啥的呢?
def open_session(self, app, request):
s = self.get_signing_serializer(app) #加密
if s is None:
return None
val = request.cookies.get(app.session_cookie_name) #去cookie中取值
if not val: #第一次访问为空执行
return self.session_class() #返回{}
max_age = total_seconds(app.permanent_session_lifetime)
try:
data = s.loads(val, max_age=max_age) #loads:并反序列化 val:原来的值
return self.session_class(data) #{"k1":123}
except BadSignature:
return self.session_class()
open_session返回啥self.session中就是啥。
现在回到我们的wsgi_app类中,
#将ctx放到“某个神奇的地方” #执行SecureCookieSessionInterface.open_session(),去cookie中获取值,并给ctx.session重新赋值。
现在才开始真正走视图函数

进入full_diapatch_request.

红框继续进入:

善后工作如何执行,继续进入:

看一下save_session:

前面的不用看,就看一下咱们用得到的。
就是完成了这一步:

其实是这样的。

最后执行

这大概就是Flask框架中sesion的请求流程。说了这么多,其实真正实现咱们想要的功能的就是两个方法:open_session,save_session.请求进来执行open_session,请求走的时候执行save_session。
默认都是调用app.session_interface。
总结
流程: 请求到来: - 请求到来之后wsgi会触发__call__方法,由__call__方法再次调用wsgi_app方法, 将请求和session相关封装到ctx = RequestContext对象中。 将app和g封装到app_ctx = AppContext对象中。 再通过LocalStack对象将ctx、app_ctx封装到Local对象中。 获取数据: 通过LocalProxy对象+偏函数,调用LocalStack去Local中获取响应ctx、app_ctx中封装的值。 请求结束: 调用LocalStack的pop方法,将ctx和app_ctx移除。

浙公网安备 33010602011771号