程序启动执行开始流程,具体工作流见《Flask源码分析之上下文请求流程(请求上下文&应用上下文)》
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()
之后的流程都和一开始相似了