在 Web 开发中,HTTP 协议是无状态的,这意味着服务器无法自动记住“你是谁”。为了解决这个问题,我们引入了 Cookie 和 Session 来维持客户端和服务器之间的状态。
在 Flask 中,这两者的使用非常优雅,但 Flask 的 Session 机制与传统的 Java/PHP 有所不同,需要特别注意。
💡 核心概念区分
| 特性 | Cookie | Session (Flask 默认实现) |
|---|---|---|
| 存储位置 | 客户端(浏览器) | 客户端(以加密签名的 Cookie 形式) |
| 安全性 | 较低,用户可查看和篡改 | 较高,用户可查看但无法篡改(有签名) |
| 容量限制 | 约 4KB | 约 4KB(受限于 Cookie 大小) |
| 适用场景 | 记住用户名、偏好设置、追踪 ID | 用户登录状态、购物车临时数据 |
⚠️ 重要提示:Flask 默认的 Session 是客户端 Session。它把数据序列化后,用
SECRET_KEY签名,然后作为 Cookie 发给浏览器。服务器端不保存任何 Session 数据。
1. 操作 Cookie
Cookie 是附加在 HTTP 请求和响应头中的。因此,读取 Cookie 用 request,设置/删除 Cookie 用 response。
代码示例:
from flask import Flask, request, make_response
app = Flask(__name__)
# 1. 设置 Cookie
@app.route('/set-cookie')
def set_cookie():
# 必须使用 make_response 将返回值包装成响应对象
resp = make_response('Cookie 设置成功!')
# 设置 Cookie: key, value, max_age(有效期,单位:秒)
# 如果不设置 max_age,则默认为会话级 Cookie(浏览器关闭即失效)
resp.set_cookie('username', 'john_doe', max_age=3600)
resp.set_cookie('theme', 'dark') # 浏览器关闭即失效
return resp
# 2. 读取 Cookie
@app.route('/get-cookie')
def get_cookie():
# 使用 request.cookies 字典获取
# 推荐使用 .get() 方法,避免 key 不存在时报 KeyError
username = request.cookies.get('username', '匿名用户')
theme = request.cookies.get('theme', 'light')
return f'你好, {username}! 你的主题设置是: {theme}'
# 3. 删除 Cookie
@app.route('/delete-cookie')
def delete_cookie():
resp = make_response('Cookie 已删除!')
# 删除 Cookie 实际上是将它的过期时间设置为过去
resp.delete_cookie('username')
resp.delete_cookie('theme')
return resp2. 操作 Session ⭐ (核心重点)
在 Flask 中使用 Session 非常简单,它就像一个字典。但有一个绝对的前提条件:必须配置 SECRET_KEY。
前提配置:
app = Flask(__name__)
# 必须设置一个复杂且保密的密钥,用于对 Session 数据进行加密签名
app.config['SECRET_KEY'] = 'your-super-secret-key-here-change-in-production'代码示例:模拟用户登录状态
from flask import Flask, session, redirect, url_for, request
app = Flask(__name__)
app.config['SECRET_KEY'] = 'super-secret-key-123'
# 1. 登录:写入 Session
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form.get('username')
# 将数据存入 session 字典
session['username'] = username
session['is_logged_in'] = True
return redirect(url_for('index'))
return '''
<form method="post">
<input type="text" name="username" placeholder="Username">
<input type="submit" value="Login">
</form>
'''
# 2. 首页:读取 Session
@app.route('/')
def index():
# 使用 .get() 安全读取
if session.get('is_logged_in'):
return f'欢迎回来, {session.get("username")}! <a href="/logout">登出</a>'
return '你还未登录,请 <a href="/login">登录</a>。'
# 3. 登出:删除 Session
@app.route('/logout')
def logout():
# 移除特定 key
session.pop('username', None)
session.pop('is_logged_in', None)
# 或者清空整个 session
# session.clear()
return redirect(url_for('index'))3. Flask Session 的“坑”与安全须知
因为 Flask 的 Session 本质上是加密签名的 Cookie,所以它继承了 Cookie 的所有物理限制和安全特性:
❌ 绝对不能做的事:
- 不要存储敏感信息:虽然数据被签名(无法篡改),但它是 Base64 编码的,用户可以轻松解码并看到内容(例如使用浏览器的开发者工具)。绝对不要存密码、身份证号、信用卡号!
- 不要存储大量数据:Cookie 的大小限制通常是 4KB。如果你在 Session 里存了一个包含几千条记录的列表,会导致请求头过大,浏览器直接报错。
✅ 安全最佳实践:
SECRET_KEY必须复杂:使用随机生成的长字符串,且不要提交到 Git。生产环境应通过环境变量读取。- 开启安全标志(在配置中):
# 仅通过 HTTPS 传输 Cookie
app.config['SESSION_COOKIE_SECURE'] = True
# 禁止 JavaScript 读取 Cookie (防 XSS 攻击)
app.config['SESSION_COOKIE_HTTPONLY'] = True
# 限制 Cookie 只能同源发送 (防 CSRF 攻击)
app.config['SESSION_COOKIE_SAMESITE'] = 'Lax' 4. 进阶:真正的“服务器端 Session”
如果你需要突破 4KB 的限制,或者绝对不想把任何数据发给客户端,你需要使用服务器端 Session。
此时,Cookie 里只存一个随机的 session_id,真正的数据存储在服务器端的 Redis 或数据库中。
实现方法:使用官方扩展 Flask-Session。
pip install Flask-Session redisfrom flask import Flask, session
from flask_session import Session
import redis
app = Flask(__name__)
# 配置 Flask-Session 使用 Redis 作为后端
app.config['SESSION_TYPE'] = 'redis'
app.config['SESSION_REDIS'] = redis.from_url('redis://127.0.0.1:6379')
app.config['SECRET_KEY'] = 'super-secret-key'
# 初始化扩展
Session(app)
@app.route('/')
def index():
# 用法与默认 Session 完全一样!
session['huge_data'] = 'A' * 10000 # 现在可以存大数据了
return 'Data stored in Redis!'📝 总结
| 操作 | 对象 | 代码示例 |
|---|---|---|
| 读 Cookie | request | request.cookies.get('key') |
| 写 Cookie | response | resp = make_response(...)resp.set_cookie('key', 'val') |
| 删 Cookie | response | resp.delete_cookie('key') |
| 读 Session | session | session.get('key') |
| 写 Session | session | session['key'] = 'value' |
| 删 Session | session | session.pop('key', None) |
掌握了 Cookie 和 Session,你的 Flask 应用就具备了“记忆”能力,可以实现用户登录、权限控制等核心功能了。
接下来,你想学习如何使用 Jinja2 模板引擎(让 HTML 页面动态化),还是直接挑战连接数据库 (Flask-SQLAlchemy)?