1. 程式人生 > >Flask中session源碼執行過程

Flask中session源碼執行過程

behavior 使用 dfs display all save -- img request

1.面向對象補充知識metaclass

創建類就可以有兩種方式:

a.普通方式

技術分享圖片
1 class Foo(object):
2  
3     def func(self):
4         print hello wupeiqi
View Code

b.特殊方式(type類的構造函數)

技術分享圖片
1 def func(self):
2     print hello wupeiqi
3  
4 Foo = type(Foo,(object,), {func: func})
5 #type第一個參數:類名
6 #type第二個參數:當前類的基類
7 #type第三個參數:類的成員
View Code

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()
View Code

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 )
View Code

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()
View Code

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)
View Code

Flask中session源碼執行過程