在 Web 开发中,HTTP 是无状态协议——服务端默认不会记住客户端的上一次请求。CookieSession 正是为了解决”记住用户”这一需求而生的。FastAPI 基于 Starlette,提供了便捷的 Cookie 操作接口和 Session 中间件支持。本文系统讲解从 Cookie 基础到 Session 实战的全链路知识。

Cookie 是服务端通过 Set-Cookie 响应头写入浏览器的一小段文本数据(通常不超过 4KB)。浏览器收到后会自动保存,并在后续请求中通过 Cookie 请求头自动回传。一个典型的 Cookie 工作流程:

1
2
客户端请求 → 服务端 Set-Cookie: user_id=abc → 浏览器保存
后续请求 → 浏览器自动带 Cookie: user_id=abc → 服务端识别用户

FastAPI 读取 Cookie 极其简单——直接将参数名声明为 Cookie 类型即可:

1
2
3
4
5
6
7
8
9
10
11
from fastapi import FastAPI, Cookie
from typing import Optional

app = FastAPI()


@app.get("/profile")
async def get_profile(user_token: Optional[str] = Cookie(None)):
if user_token is None:
return {"message": "未登录"}
return {"user_token": user_token, "message": "欢迎回来"}

访问 http://localhost:8000/profile ——如果浏览器没有名为 user_token 的 Cookie,user_token 就是 None,返回”未登录”。

如果 Cookie 名和 Python 变量名不同(比如 Cookie 名带横线),可以用 alias 参数:

1
2
3
4
5
@app.get("/items/")
async def read_items(
session_id: Optional[str] = Cookie(None, alias="session-id")
):
return {"session_id": session_id}

设置 Cookie 需要操作 Response 对象。FastAPI 提供了 Response 参数注入,调用 set_cookie() 即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from fastapi import FastAPI, Response
from datetime import datetime, timedelta

app = FastAPI()


@app.post("/login")
async def login(username: str, response: Response):
# 登录逻辑(此处简化)
token = f"token_{username}_{datetime.now().timestamp()}"

# 设置 Cookie
response.set_cookie(
key="user_token",
value=token,
max_age=3600, # 有效期,单位秒
httponly=True, # 禁止 JS 读取,防 XSS
secure=True, # 仅 HTTPS 传输
samesite="lax", # 防 CSRF
path="/", # Cookie 生效路径
)
return {"message": "登录成功"}
参数 说明 推荐值
key Cookie 名称 自定义
value Cookie 值(字符串)
max_age 过期时间(秒),优先级高于 expires 按需
expires 具体的过期 datetime
path 生效路径,/ 表示全站 /
domain 生效域名,默认当前域
secure 仅 HTTPS 传输 True
httponly 禁止 JavaScript 访问 True
samesite 跨站请求控制:lax / strict / none lax

安全提示:生产环境务必开启 httponlysecuresamesitehttponly 能防止 XSS 窃取 Cookie,samesite=lax 能防御大部分 CSRF 攻击。

删除 Cookie 的本质是设置一个立即过期的同名 Cookie:

1
2
3
4
5
6
7
8
9
10
@app.post("/logout")
async def logout(response: Response):
response.delete_cookie(
key="user_token",
path="/",
secure=True,
httponly=True,
samesite="lax",
)
return {"message": "已退出登录"}

delete_cookie() 内部会设置 max_age=0expires=0,浏览器收到后就会删除该 Cookie。注意删除时的 pathdomain 等参数必须和设置时一致,否则浏览器不会删除。

如果你的路由函数返回的不是简单字典,而是自定义 Response,同样可以操作 Cookie:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from fastapi.responses import JSONResponse


@app.post("/custom-login")
async def custom_login(username: str):
token = f"custom_token_{username}"

content = {"message": "登录成功"}
response = JSONResponse(content=content)
response.set_cookie(
key="user_token",
value=token,
max_age=3600,
httponly=True,
secure=True,
samesite="lax",
)
return response

Session 的实现

Session 本质上是”存储在服务端的用户数据”,客户端只持有一个 Session ID(通常放在 Cookie 中)。FastAPI 没有内置 Session 机制,但 Starlette 提供了 SessionMiddleware,开箱即用。

安装与配置

SessionMiddleware 需要 itsdangerous 库用于签名:

1
pip install itsdangerous

在 FastAPI 应用中添加 Session 中间件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from fastapi import FastAPI, Request
from starlette.middleware.sessions import SessionMiddleware

app = FastAPI()

# 添加 Session 中间件
app.add_middleware(
SessionMiddleware,
secret_key="your-secret-key-change-in-production",
session_cookie="session_id", # Cookie 名称,默认 "session"
max_age=3600, # 过期秒数,默认 14 天
same_site="lax",
https_only=False, # 开发环境 False,生产环境 True
)

@app.get("/set-session")
async def set_session(request: Request):
request.session["username"] = "张三"
request.session["role"] = "admin"
return {"message": "Session 已设置"}


@app.get("/get-session")
async def get_session(request: Request):
username = request.session.get("username", "游客")
role = request.session.get("role", "anonymous")
return {"username": username, "role": role}


@app.get("/clear-session")
async def clear_session(request: Request):
request.session.clear()
return {"message": "Session 已清除"}

SessionMiddleware 工作原理

  1. 读取请求 Cookie 中名为 session(或自定义名)的值
  2. secret_key 验签并解密,还原为 Python 字典挂载到 request.session
  3. 路由函数可以像操作普通字典一样读写 request.session
  4. 响应时,中间件将 request.session 序列化、签名后写回 Cookie

核心要点:Session 数据是加密签名后存在 Cookie 中的(客户端 Session),而不是存在服务端内存或数据库。优点是无需服务端存储,天然支持分布式;缺点是 Cookie 有 4KB 大小限制,且不应存放敏感数据(加密不等于安全,密钥泄露即全部暴露)。

实操:Cookie + Session 实现登录态

下面是一个完整的登录验证示例,展示 Cookie 和 Session 如何配合使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
from fastapi import FastAPI, Request, Response, HTTPException, Cookie
from starlette.middleware.sessions import SessionMiddleware
from typing import Optional

app = FastAPI()

app.add_middleware(
SessionMiddleware,
secret_key="super-secret-key-2026",
session_cookie="sid",
max_age=86400, # 24 小时
same_site="lax",
)


# 模拟的用户数据库
fake_users = {"admin": "password123"}


@app.post("/api/login")
async def api_login(
request: Request,
response: Response,
username: str,
password: str,
):
"""用户登录接口"""
if username not in fake_users or fake_users[username] != password:
raise HTTPException(status_code=401, detail="用户名或密码错误")

# 将用户信息存入 Session
request.session["user"] = username
request.session["login_time"] = "2026-07-19"

# 同时设置一个独立的持久化 Cookie(比如"记住我"功能)
response.set_cookie(
key="remember_me",
value="1",
max_age=86400 * 30, # 30 天
httponly=True,
secure=True,
samesite="lax",
)
return {"message": f"欢迎 {username}!登录成功"}


@app.get("/api/me")
async def get_current_user(request: Request):
"""获取当前登录用户信息"""
user = request.session.get("user")
if user is None:
raise HTTPException(status_code=401, detail="请先登录")
return {
"username": user,
"login_time": request.session.get("login_time"),
}


@app.post("/api/logout")
async def api_logout(request: Request, response: Response):
"""用户退出登录"""
request.session.clear() # 清除 Session
response.delete_cookie("remember_me") # 清除记住我 Cookie
return {"message": "已退出登录"}

测试流程:POST /api/login → 浏览器自动保存 Cookie → GET /api/me 返回用户信息 → POST /api/logout 清除所有状态。

维度 Cookie Session (Starlette)
数据存储位置 客户端浏览器 Cookie 中(加密签名)
容量限制 每个 Cookie 约 4KB 受 Cookie 总大小限制
安全性 明文,可被用户篡改 加密签名,篡改可检测
过期控制 max_age / expires max_age(中间件参数)
适用场景 记住偏好、跟踪标识 登录态、用户数据

小结

Cookie 和 Session 是 Web 开发中管理用户状态的两大基石:

  • Cookie 适合存放轻量、非敏感的客户端标识,通过 set_cookie() 设置、Cookie() 读取
  • Session 通过 SessionMiddleware 实现,数据加密签名存储在 Cookie 中,适合存放登录态等需要防篡改的信息
  • 安全是底线:生产环境务必启用 httponlysecuresamesite,且 secret_key 绝对不可泄露

掌握了 Cookie 和 Session,你就能构建出有”记忆”的 Web 应用——记住用户偏好、维护登录状态、实现购物车功能,全都离不开它们。