1.flask对session的处理机制
1.1、 flask的session处理机制(内置,将session保存到加密的cookie中去实现)
- 请求来的时候,获取随机字符串,(这些都放在内存)
存在,到数据库(或者文件,某个地方)中获取个人数据
不存在,创建,创建对象(随机字符串,{存放用户的数据的容器})
- 视图:操作内存中的对象(随机字符串,{用户的数据})
- 响应:内存中的对象(随机字符串,{用户的数据})
将数据保存到数据库
随机字符串写在用户的cookie中
1.2、源码分析、
a.请求进来执行app的__call__()方法,然后执行wsgi_app()方法
1 def wsgi_app(self, environ, start_response): 2 # 1、在request_context这里,实例化RequestContext()对象,environ是请求的相关所有数据 3 # 封装了request,session,app等 4 ctx = self.request_context(environ) 5 6 # 2、执行RequestContext()对象的push 7 ctx.push() 8 # push内部创建了app_ctx:AppContext(self)对象, 9 # push操作之后,session就有值了,请求第一次进来,此时的session=特殊的空字典 10 11 error = None 12 # try的内部其实是在做视图函数的处理 13 try: 14 try: 15 response = self.full_dispatch_request() # 这里找视图函数并执行 16 except Exception as e: 17 error = e 18 response = self.handle_exception(e) # 当在处理视图的时候出错执行这个函数 19 except: 20 error = sys.exc_info()[1] 21 raise 22 # 给用户返回信息 23 return response(environ, start_response) 24 finally: 25 if self.should_ignore_error(error): 26 error = None 27 # 请求结束:执行RequestContext()对象的auto_pop函数 28 ctx.auto_pop(error)
a-1. 执行 ctx.push()
1 def push(self): 2 3 # app_ctx是LocalStack类的对象。请求一开始进来,app_ctx为空 4 app_ctx = _app_ctx_stack.top 5 if app_ctx is None or app_ctx.app != self.app: 6 # 第一次进来的时候app没有值,这里是实例化AppContext类对象的操作 7 # app_ctx.g 相当于字典,可以存放before_request的时候传的值,一次使用 8 app_ctx = self.app.app_context() 9 # 执行AppContext类对象的push方法 10 app_ctx.push() 11 self._implicit_app_ctx_stack.append(app_ctx) 12 else: 13 self._implicit_app_ctx_stack.append(None) 14 15 if hasattr(sys, 'exc_clear'): 16 sys.exc_clear() 17 18 # _request_ctx_stack就是对LocalStark的对象,执行LocalStark的push 19 _request_ctx_stack.push(self) 20 21 # 获取session信息, 22 # 请求一开始进来给session赋值,执行当前app的open_session方法, 23 # self.session实际就是SecureCookieSession()对象 24 # 由于session此次的赋值是在ctx的push里面赋值,但是Local类中封装了ctx,所以这里的session被赋值,Local中的session也会变化 25 self.session = self.app.open_session(self.request) 26 if self.session is None: 27 self.session = self.app.make_null_session()
a-1-1、执行 self.app.open_session(self.request)
1 def open_session(self, request): 2 # self.session_interface = SecureCookieSessionInterface() 3 # 执行SecureCookieSessionInterface()的open_session方法 4 return self.session_interface.open_session(self, request)
a-1-2、执行SecureCookieSessionInterface()的open_session方法
1 def open_session(self, app, request): 2 # s获取一个加密规则 3 s = self.get_signing_serializer(app) 4 if s is None: 5 return None 6 7 # 去用户请求的cookie中获取原来返回给用户的随机字符串 8 # 即key为session的值 9 val = request.cookies.get(app.session_cookie_name) 10 11 if not val: 12 # 请求第一次进来的时候val没有值,返回一个特殊的空字典 13 # session_class = SecureCookieSession 14 # SecureCookieSession继承了一个继承了字典的类,相当于给session创建了一个特殊的字典 15 return self.session_class() 16 17 max_age = total_seconds(app.permanent_session_lifetime) 18 19 try: 20 # 把用户浏览器中的cookie的key为session的值解密成字典(dict) 21 data = s.loads(val, max_age=max_age) 22 # 再把这个字典转换成特殊的字典,也放到了Local中的ctx中 23 return self.session_class(data) 24 25 except BadSignature: 26 return self.session_class()
b.在视图函数中执行 session['xxx'] = 123
1 # session['xxx']=123 ---> 执行LocalProxy()的__setitem__()方法 2 session = LocalProxy(partial(_lookup_req_object, 'session'))
b-1.执行LocalProxy()的__setitem__()方法
1 def __setitem__(self, key, value): 2 # 1.obj = self._get_current_object():执行偏函数,拿到对应的session对象,即一个特殊的空字典 3 # 2.obj[key] = value 执行SecureCookieSession类的__setitem__()方法,把数据放到了特殊的空字典中 4 self._get_current_object()[key] = value
c.请求离开的时候 wsgi_app()--->full_dispatch_request()--->finalize_request()--->process_response()
1 def process_response(self, response): 2 ctx = _request_ctx_stack.top 3 bp = ctx.request.blueprint 4 funcs = ctx._after_request_functions 5 if bp is not None and bp in self.after_request_funcs: 6 funcs = chain(funcs, reversed(self.after_request_funcs[bp])) 7 if None in self.after_request_funcs: 8 funcs = chain(funcs, reversed(self.after_request_funcs[None])) 9 for handler in funcs: 10 response = handler(response) 11 if not self.session_interface.is_null_session(ctx.session): 12 # ctx.session就是之前创建的特殊的自典,response就是返回值 13 self.save_session(ctx.session, response) 14 return response
c-1.执行 save_session
1 def save_session(self, session, response): 2 # session_interface = SecureCookieSessionInterface 3 # 执行SecureCookieSessionInterface()的save_session() 4 return self.session_interface.save_session(self, session, response)
c-2.执行SecureCookieSessionInterface()的save_session()
def save_session(self, app, session, response): domain = self.get_cookie_domain(app) path = self.get_cookie_path(app) if not session: # session没有值 if session.modified: # 只要修改session,modified就变化,session是空的并且修改过,表示删除了session # 删除cookie response.delete_cookie(app.session_cookie_name, domain=domain, path=path) return if not self.should_set_cookie(app, session): return httponly = self.get_cookie_httponly(app) secure = self.get_cookie_secure(app) expires = self.get_expiration_time(app, session) # dict(session) ---> 转换成自典 # get_signing_serializer ---> 序列化 # val ---> 加密之后的值 val = self.get_signing_serializer(app).dumps(dict(session)) # 将数据加密之后,写到cookie中,flask中默认把session中的数据写到cookie中 response.set_cookie(app.session_cookie_name, val, expires=expires, httponly=httponly, domain=domain, path=path, secure=secure)
2.自定义
3.flask组件