1.Cookie、 Session 机制剖析
- 产⽣过程
- 浏览器: 向服务器发送请求
- 服务器: 接受并创建 session 对象 (该对象包含⼀个 session_id)
- 服务器: 执⾏ views 函数, 并得到⼀个 response 对象
- 服务器: 执⾏ response.set_cookie(‘sessionid’, session_id) 将 session_id 写⼊ cookie
- 服务器: 将 response 传回浏览器
- 浏览器: 读取 response 报⽂, 从 Cookies 取出 session_id 并保存
- 后续请求
- 浏览器: 向服务器发送请求, session_id 随 Cookies ⼀同发给 Server
- 服务器: 从 Headers 的 Cookies 中取出 session_id
- 服务器: 根据 session_id 找出对应的数据, 确认客户端身份
- Django 中的代码实现
class SessionMiddleware(MiddlewareMixin):
def __init__(self, get_response=None):
self.get_response = get_response
engine = import_module(settings.SESSION_ENGINE)
self.SessionStore = engine.SessionStore # 设置 Session 存储类
def process_request(self, request):
# 从 Cookie 获取 sessionid
session_key = request.COOKIES.get('session_id')
# 通过 session_key 获取之前保存的数据
request.session = self.SessionStore(session_key)
def process_response(self, request, response):
try:
# View 函数结束后, 获取 session 状态
accessed = request.session.accessed
modified = request.session.modified
empty = request.session.is_empty()
except AttributeError:
pass
else:
# 如果 Cookie 中有 sessionid, 但 session 为空,
# 说明 view 中执⾏过 session.flush 等操作,
# 直接删除 Cookie 中的 session
if 'session_id' in request.COOKIES and empty:
response.delete_cookie(
settings.SESSION_COOKIE_NAME,
path=settings.SESSION_COOKIE_PATH,
domain=settings.SESSION_COOKIE_DOMAIN,
)
else:
if accessed:
patch_vary_headers(response, ('Cookie',))
if (modified or settings.SESSION_SAVE_EVERY_REQUEST) and not empty:
# 设置过期时间
if request.session.get_expire_at_browser_close():
max_age = None
expires = None
else:
max_age = request.session.get_expiry_age()
expires_time = time.time() + max_age
expires = cookie_date(expires_time)
# 保存会话数据, 并刷新客户端 Cookie
if response.status_code != 500:
try:
request.session.save()
except UpdateError:
raise SuspiciousOperation(
"The request's session was deleted before the "
"request completed. The user may have logged "
"out in a concurrent request, for example."
)
# 让客户端将 sessionid 添加到 Cookie 中
response.set_cookie(
'session_id',
request.session.session_key,
max_age=max_age,
expires=expires,
domain=settings.SESSION_COOKIE_DOMAIN,
path=settings.SESSION_COOKIE_PATH,
secure=settings.SESSION_COOKIE_SECURE or None,
httponly=settings.SESSION_COOKIE_HTTPONLY or None,
)
return response