1. SessionInterface抽象基类
SessionInterface定义了Session存储后端需要实现的核心接口。
| 属性/方法 | 说明 |
|---|---|
null_session_class |
当Session不可用时使用的类,默认为NullSession |
pickle_based |
Session是否基于pickle序列化,默认为False |
open_session(app, request) |
从请求中读取Session数据,返回SessionMixin实例或None |
save_session(app, session, response) |
将Session数据保存到响应中 |
make_null_session(app) |
创建空Session,open_session返回None时自动调用 |
is_null_session(obj) |
判断是否为NullSession实例 |
2. Cookie选项方法
以下方法用于获取Session Cookie的各项属性,可被子类重写:
| 方法 | 说明 |
|---|---|
get_cookie_name(app) |
获取Cookie名称,默认读取SESSION_COOKIE_NAME配置 |
get_cookie_domain(app) |
获取Cookie Domain,默认读取SESSION_COOKIE_DOMAIN |
get_cookie_path(app) |
获取Cookie Path,默认读取SESSION_COOKIE_PATH或APPLICATION_ROOT |
get_cookie_httponly(app) |
获取HttpOnly标志,默认读取SESSION_COOKIE_HTTPONLY |
get_cookie_secure(app) |
获取Secure标志,默认读取SESSION_COOKIE_SECURE |
get_cookie_samesite(app) |
获取SameSite值,默认读取SESSION_COOKIE_SAMESITE |
get_cookie_partitioned(app) |
获取Partitioned标志,默认读取SESSION_COOKIE_PARTITIONED(v3.1+) |
get_expiration_time(app, session) |
获取Session过期时间,永久Session返回now + lifetime |
should_set_cookie(app, session) |
判断是否需要设置Cookie |
3. 内置实现
| 类 | 说明 |
|---|---|
SecureCookieSessionInterface |
默认实现 。使用itsdangerous签名Cookie存储Session数据 |
SecureCookieSession |
基于CallbackDict的Session类,检测顶层键的修改自动设置modified=True |
NullSession |
未设置SECRET_KEY时使用的占位Session,读取正常但修改时报错 |
SessionMixin |
Session类的Mixin,提供permanent、new、modified、accessed属性 |
4. 替换默认Session实现
自定义内存Session(示例)
from flask import Flask from flask.sessions import SessionInterface, SessionMixin from uuid import uuid4 # 自定义Session类(存储用户数据) class MySession(dict, SessionMixin): def __init__(self, session_id=None, data=None): super().__init__() self.session_id = session_id or str(uuid4()) if data: self.update(data) self.permanent = False # 自定义Session接口(内存存储) class MySessionInterface(SessionInterface): # 模拟数据库存储(实际生产环境应使用Redis等) _store = {} def open_session(self, app, request): # 从Cookie中获取session_id session_id = request.cookies.get("my_session_id") if session_id and session_id in self._store: data = self._store[session_id] return MySession(session_id, data) # 创建新Session return MySession() def save_session(self, app, session, response): if not session: return # 如果Session为空,删除Cookie if not session: response.delete_cookie("my_session_id") return # 保存数据到存储 self._store[session.session_id] = dict(session) # 设置Cookie response.set_cookie( "my_session_id", session.session_id, max_age=app.permanent_session_lifetime.total_seconds() if session.permanent else None, httponly=True, secure=app.config.get("SESSION_COOKIE_SECURE", False), samesite=app.config.get("SESSION_COOKIE_SAMESITE", "Lax") ) # 应用配置 app = Flask(__name__) app.secret_key = "dev-secret" app.session_interface = MySessionInterface() @app.route("/") def index(): session["count"] = session.get("count", 0) + 1 return f"访问次数: {session['count']}"
5. 使用Redis存储Session(生产级示例)
import redis import pickle from flask import Flask from flask.sessions import SessionInterface, SessionMixin from uuid import uuid4 from datetime import timedelta class RedisSession(dict, SessionMixin): """Redis存储的Session类""" def __init__(self, session_id=None, data=None, expiry=None): super().__init__() self.session_id = session_id or str(uuid4()) self.permanent = False self.expiry = expiry if data: self.update(data) class RedisSessionInterface(SessionInterface): """使用Redis存储Session""" def __init__(self, redis_client, key_prefix="session:"): self.redis = redis_client self.key_prefix = key_prefix def _get_key(self, session_id): return f"{self.key_prefix}{session_id}" def open_session(self, app, request): session_id = request.cookies.get(app.config.get("SESSION_COOKIE_NAME", "session")) if session_id: key = self._get_key(session_id) data = self.redis.get(key) if data: try: data_dict = pickle.loads(data) return RedisSession(session_id, data_dict) except: pass return RedisSession() def save_session(self, app, session, response): if not session: return key = self._get_key(session.session_id) # 如果Session为空,删除Redis数据并清除Cookie if not session: self.redis.delete(key) response.delete_cookie(app.config["SESSION_COOKIE_NAME"]) return # 计算过期时间 if session.permanent: lifetime = app.config.get("PERMANENT_SESSION_LIFETIME", timedelta(days=31)) else: lifetime = timedelta(days=1) # 序列化并保存到Redis self.redis.setex(key, int(lifetime.total_seconds()), pickle.dumps(dict(session))) # 设置Cookie response.set_cookie( app.config["SESSION_COOKIE_NAME"], session.session_id, max_age=int(lifetime.total_seconds()) if session.permanent else None, httponly=app.config.get("SESSION_COOKIE_HTTPONLY", True), secure=app.config.get("SESSION_COOKIE_SECURE", False), samesite=app.config.get("SESSION_COOKIE_SAMESITE", "Lax") ) # 使用 import redis r = redis.Redis(host="localhost", port=6379, db=0) app = Flask(__name__) app.secret_key = "dev-secret" app.session_interface = RedisSessionInterface(r) @app.route("/") def index(): session["views"] = session.get("views", 0) + 1 return f"访问次数: {session['views']}"
6. 什么时候需要自定义SessionInterface
| 场景 | 说明 |
|---|---|
| 多服务器/负载均衡 | 默认签名Cookie在单服务器可用,多服务器间需共享Session存储 |
| Session数据量较大 | Cookie有4KB限制,外部存储无此限制 |
| 需要服务端Session控制 | 如强制下线、Session黑名单等 |
| 与现有系统集成 | 需对接已有的Session存储体系 |
| 审计和安全要求 | 需要完整的服务端Session日志 |
7. 不同Session方案对比
| 存储方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 签名Cookie(默认) | 无状态、无需服务端存储、部署简单 | 4KB限制、数据可见、无法主动失效 | 单机应用、轻量Session |
| Redis | 高性能、支持过期、多服务器共享 | 需要额外服务、网络延迟 | 分布式应用、高并发 |
| 数据库 | 持久化、支持复杂查询 | 性能较低 | 对持久性要求高的场景 |
| Memcached | 高性能 | 不支持持久化 | 缓存型Session |
8. SessionInterface API速查表
| 类别 | 方法 | 说明 |
|---|---|---|
| 核心 | open_session(app, request) |
从请求加载Session数据 |
| 核心 | save_session(app, session, response) |
保存Session到响应 |
| Cookie | get_cookie_name(app) |
Cookie名称 |
| Cookie | get_cookie_secure(app) |
Secure标志 |
| Cookie | get_cookie_httponly(app) |
HttpOnly标志 |
| Cookie | get_cookie_samesite(app) |
SameSite值 |
| Cookie | get_expiration_time(app, session) |
过期时间 |
| 工具 | should_set_cookie(app, session) |
是否设置Cookie |
| 工具 | make_null_session(app) |
创建空Session |
小结
本章全面讲解了Flask Session Interface的完整API。SessionInterface是Session存储的底层抽象,通过open_session(app, request)从请求加载Session数据,通过save_session(app, session, response)将Session保存到响应;Cookie相关方法(get_cookie_name、get_cookie_secure、get_cookie_httponly、get_cookie_samesite等)可被子类重写以自定义Cookie属性;Flask默认使用SecureCookieSessionInterface(签名Cookie存储);通过替换app.session_interface可切换为Redis、数据库等外部存储,解决多服务器共享、数据量限制等问题。自定义SessionInterface是实现分布式Session管理的核心手段。