flask之自己的session和三方的flask-session组件

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组件

原文地址:https://www.cnblogs.com/chitalu/p/8746425.html