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移除。