Flask中session源码执行过程
Posted chenjunkan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flask中session源码执行过程相关的知识,希望对你有一定的参考价值。
1.面向对象补充知识metaclass
创建类就可以有两种方式:
a.普通方式
1 class Foo(object): 2 3 def func(self): 4 print ‘hello wupeiqi‘
b.特殊方式(type类的构造函数)
1 def func(self): 2 print ‘hello wupeiqi‘ 3 4 Foo = type(‘Foo‘,(object,), {‘func‘: func}) 5 #type第一个参数:类名 6 #type第二个参数:当前类的基类 7 #type第三个参数:类的成员
c.metaclass代码示例
1 class MyType(type): 2 def __init__(self,*args,**kwargs): 3 print(‘init‘) 4 super(MyType,self).__init__(*args,**kwargs) 5 6 def __call__(self, *args, **kwargs): 7 print(‘call本质:调用类的__new__,再调用类的__init__‘) 8 return super(MyType,self).__call__( *args, **kwargs) 9 10 11 class Foo(metaclass=MyType): 12 pass 13 14 class Bar(Foo): 15 pass 16 17 obj = Bar()
2.session源码分析
1 请求到来: 2 1.app.__call__-->app.wsgi_app-->ctx.push();此时在threadinglocal中有ctx.app,ctx.request,ctx.session[],其中session中是没有值的 3 2.self.session = session_interface.open_session(self.app,self.request) 4 说明: 5 1.session_interface = SecureCookieSessionInterface(),因此self.session = SecureCookieSessionInterface() 6 2.执行open_session 7 def open_session(self, app, request): 8 s = self.get_signing_serializer(app) 9 if s is None: 10 return None 11 val = request.cookies.get(app.session_cookie_name) 12 if not val: 13 return self.session_class() 14 max_age = total_seconds(app.permanent_session_lifetime) 15 try: 16 data = s.loads(val, max_age=max_age) 17 return self.session_class(data) 18 except BadSignature: 19 return self.session_class() 20 3.session_class其实是一个特殊的dict对象 21 a.session_class = SecureCookieSession 22 b.class SecureCookieSession(CallbackDict, SessionMixin): 23 c.class CallbackDict(UpdateDictMixin, dict): 24 d.class dict(object): 25 26 4.在请求结束后就会执行save_session 27 def save_session(self, app, session, response): 28 domain = self.get_cookie_domain(app) 29 path = self.get_cookie_path(app) 30 31 if session.accessed: 32 response.vary.add(‘Cookie‘) 33 34 if not self.should_set_cookie(app, session): 35 return 36 37 httponly = self.get_cookie_httponly(app) 38 secure = self.get_cookie_secure(app) 39 samesite = self.get_cookie_samesite(app) 40 expires = self.get_expiration_time(app, session) 41 val = self.get_signing_serializer(app).dumps(dict(session)) 42 response.set_cookie( 43 app.session_cookie_name, 44 val, 45 expires=expires, 46 httponly=httponly, 47 domain=domain, 48 path=path, 49 secure=secure, 50 samesite=samesite 51 )
3.自定义MySessionInterFace
1 from flask import Flask,session 2 3 4 app = Flask(__name__) 5 app.secret_key = ‘suijksdfsd‘ 6 7 8 import json 9 class MySessionInterFace(object): 10 def open_session(self,app,request): 11 return {} 12 13 def save_session(self, app, session, response): 14 response.set_cookie(‘session_idfsdfsdfsdf‘,json.dumps(session)) 15 16 def is_null_session(self, obj): 17 """Checks if a given object is a null session. Null sessions are 18 not asked to be saved. 19 20 This checks if the object is an instance of :attr:`null_session_class` 21 by default. 22 """ 23 return False 24 25 app.session_interface = MySessionInterFace() 26 27 @app.route(‘/‘) 28 def index(): 29 # 特殊空字典 30 # 在local的ctx中找到session 31 # 在空字典中写值 32 # 在空字典中获取值 33 session[‘xxx‘] = 123 34 35 36 return ‘Index‘ 37 38 # # 一旦请求到来 39 app.__call__ 40 app.wsgi_app 41 app.session_interface 42 app.open_session 43 44 45 if __name__ == ‘__main__‘: 46 47 app.run()
4.使用flask_session
1 from flask import Flask, session 2 3 app = Flask(__name__) 4 app.secret_key = ‘suijksdfsd‘ 5 6 # 7 from redis import Redis 8 from flask_session import RedisSessionInterface 9 10 conn = Redis() 11 app.session_interface = RedisSessionInterface(conn, key_prefix=‘__‘, use_signer=False, permanent=True) 12 13 from redis import Redis 14 from flask.ext.session import Session 15 16 app.config[‘SESSION_TYPE‘] = ‘redis‘ 17 app.config[‘SESSION_REDIS‘] = Redis(host=‘192.168.0.94‘, port=‘6379‘) 18 Session(app) 19 20 21 @app.route(‘/‘) 22 def index(): 23 session[‘xxx‘] = 123 24 return ‘Index‘ 25 26 27 if __name__ == ‘__main__‘: 28 app.run() 29 30 说明:使用session必须要有secret_key 31 32 源码说明:实际上RedisSessionInterface是继承SessionInterface 33 app.session_interface = RedisSessionInterface(conn, key_prefix=‘__‘, use_signer=False, permanent=True) 34 35 class RedisSessionInterface(SessionInterface): 36 serializer = pickle 37 session_class = RedisSession 38 39 def __init__(self, redis, key_prefix, use_signer=False, permanent=True): 40 if redis is None: 41 from redis import Redis 42 redis = Redis() 43 self.redis = redis 44 self.key_prefix = key_prefix 45 self.use_signer = use_signer 46 self.permanent = permanent 47 48 def open_session(self, app, request): 49 sid = request.cookies.get(app.session_cookie_name) 50 if not sid: 51 sid = self._generate_sid() 52 return self.session_class(sid=sid, permanent=self.permanent) 53 if self.use_signer: 54 signer = self._get_signer(app) 55 if signer is None: 56 return None 57 try: 58 sid_as_bytes = signer.unsign(sid) 59 sid = sid_as_bytes.decode() 60 except BadSignature: 61 sid = self._generate_sid() 62 return self.session_class(sid=sid, permanent=self.permanent) 63 64 if not PY2 and not isinstance(sid, text_type): 65 sid = sid.decode(‘utf-8‘, ‘strict‘) 66 val = self.redis.get(self.key_prefix + sid) 67 if val is not None: 68 try: 69 data = self.serializer.loads(val) 70 return self.session_class(data, sid=sid) 71 except: 72 return self.session_class(sid=sid, permanent=self.permanent) 73 return self.session_class(sid=sid, permanent=self.permanent) 74 75 def save_session(self, app, session, response): 76 domain = self.get_cookie_domain(app) 77 path = self.get_cookie_path(app) 78 if not session: 79 if session.modified: 80 self.redis.delete(self.key_prefix + session.sid) 81 response.delete_cookie(app.session_cookie_name, 82 domain=domain, path=path) 83 return 84 85 # Modification case. There are upsides and downsides to 86 # emitting a set-cookie header each request. The behavior 87 # is controlled by the :meth:`should_set_cookie` method 88 # which performs a quick check to figure out if the cookie 89 # should be set or not. This is controlled by the 90 # SESSION_REFRESH_EACH_REQUEST config flag as well as 91 # the permanent flag on the session itself. 92 # if not self.should_set_cookie(app, session): 93 # return 94 95 httponly = self.get_cookie_httponly(app) 96 secure = self.get_cookie_secure(app) 97 expires = self.get_expiration_time(app, session) 98 val = self.serializer.dumps(dict(session)) 99 self.redis.setex(name=self.key_prefix + session.sid, value=val, 100 time=total_seconds(app.permanent_session_lifetime)) 101 if self.use_signer: 102 session_id = self._get_signer(app).sign(want_bytes(session.sid)) 103 else: 104 session_id = session.sid 105 response.set_cookie(app.session_cookie_name, session_id, 106 expires=expires, httponly=httponly, 107 domain=domain, path=path, secure=secure)
以上是关于Flask中session源码执行过程的主要内容,如果未能解决你的问题,请参考以下文章
Flask框架cbv的写法请求与响应请求扩展session源码分析闪现
flask-day2——cbv源码分析模版语法请求与响应session及源码分析闪现请求扩展
flask Flask-Login 插件及继承 UserMixin 类login_user 源码分析session源码分析