flask内置session源码分析

程序启动执行开始流程,具体工作流见《Flask源码分析之上下文请求流程(请求上下文&应用上下文)》

  1. session的来源
app.run()->
run_simple(host, port, self, **options)->
__call__(self, environ, start_response)->
wsgi_app(self, environ, start_response)->
ctx.push()-> 
self.session = self.app.open_session(self.request)

重点:

self.session = self.app.open_session(self.request)
# open_session为app.open_session

def open_session(self, request):
    # session_interface = SecureCookieSessionInterface()
    # 所以open_session为SecureCookieSessionInterface中的方法
    return self.session_interface.open_session(self, request)

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)
    if not val:
        return self.session_class() # 返回一个特殊的空字典,所以session就是这个空字典
    max_age = total_seconds(app.permanent_session_lifetime)
    try:
        data = s.loads(val, max_age=max_age)
        # session_class = SecureCookieSession 
        return self.session_class(data) 
    except BadSignature:
        return self.session_class()

2.session的使用

from flask import Flask, session

app = Flask(__name__)

@app.route("/")
def hello():
    session["k"] = "123456"
    return "hello word"

# 源码开始
session = LocalProxy(partial(_lookup_req_object, 'session'))
# 偏函数先获取到session
session["k"] = "123456" # 这段代码就相当与执行了LocalProxy中的__setitem__方法

def __setitem__(self, key, value):
    # _get_current_object    
    # return getattr(self.__local, self.__name__) 在local中获取session字典
    self._get_current_object()[key] = value # 赋值到session字典中

3.请求结束后关于session

response = self.full_dispatch_request()->
return self.finalize_request(rv)->
response = self.process_response(response)->
self.save_session(ctx.session, response)

# 源码
def save_session(self, session, response):
    # session_interface = SecureCookieSessionInterface()
    # SecureCookieSessionInterface.save_session()
    return self.session_interface.save_session(self, session, response)

# sava_session分析
def save_session(self, app, session, response):
      domain = self.get_cookie_domain(app)
      path = self.get_cookie_path(app)

      # Delete case.  If there is no session we bail early.
      # If the session was modified to be empty we remove the
      # whole cookie.
      if not session:
          if session.modified:
              response.delete_cookie(app.session_cookie_name,
                                     domain=domain, path=path)
          return

      # Modification case.  There are upsides and downsides to
      # emitting a set-cookie header each request.  The behavior
      # is controlled by the :meth:`should_set_cookie` method
      # which performs a quick check to figure out if the cookie
      # should be set or not.  This is controlled by the
      # SESSION_REFRESH_EACH_REQUEST config flag as well as
      # the permanent flag on the session itself.
      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)
      val = self.get_signing_serializer(app).dumps(dict(session)) # 序列化session,生成加密串
      # val为序列化之后的session加密串
      # 所以最后session信息是放到了cookie中,键为session名字,浏览器验证理论成功
      response.set_cookie(app.session_cookie_name, val,
                          expires=expires, httponly=httponly,
                          domain=domain, path=path, secure=secure)

4.session回顾

# 我们知道了session最终是存到了cookie中
# 回过头继续看open_session这个方法

def open_session(self, app, request):
    s = self.get_signing_serializer(app)
    if s is None:
        return None
    # 这一步从cookie中取到session的加密串
    val = request.cookies.get(app.session_cookie_name)
    if not val:
        # 如果没有获取到就返回空的,否则返回
        # self.session_class(data)
        return self.session_class()
    max_age = total_seconds(app.permanent_session_lifetime)
    try:
        data = s.loads(val, max_age=max_age) # 反序列化cookie中得到的加密串,生成session信息
        # session_class = SecureCookieSession 
        return self.session_class(data)  # 把获取到的session封装到seesion特殊字典中
    except BadSignature:
        return self.session_class()

之后的流程都和一开始相似了

你可能感兴趣的:(python,flask_session)