在 Web 开发中,HTTP 是无状态协议——服务端默认不会记住客户端的上一次请求。Cookie 和 Session 正是为了解决”记住用户”这一需求而生的。FastAPI 基于 Starlette,提供了便捷的 Cookie 操作接口和 Session 中间件支持。本文系统讲解从 Cookie 基础到 Session 实战的全链路知识。
Cookie 的基本概念 Cookie 是服务端通过 Set-Cookie 响应头写入浏览器的一小段文本数据(通常不超过 4KB)。浏览器收到后会自动保存,并在后续请求中通过 Cookie 请求头自动回传。一个典型的 Cookie 工作流程:
1 2 客户端请求 → 服务端 Set-Cookie: user_id=abc → 浏览器保存 后续请求 → 浏览器自动带 Cookie: user_id=abc → 服务端识别用户
读取 Cookie FastAPI 读取 Cookie 极其简单——直接将参数名声明为 Cookie 类型即可:
1 2 3 4 5 6 7 8 9 10 11 from fastapi import FastAPI, Cookiefrom 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 设置 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, Responsefrom datetime import datetime, timedeltaapp = FastAPI() @app.post("/login" ) async def login (username: str , response: Response ): token = f"token_{username} _{datetime.now().timestamp()} " response.set_cookie( key="user_token" , value=token, max_age=3600 , httponly=True , secure=True , samesite="lax" , path="/" , ) return {"message" : "登录成功" }
set_cookie 参数详解
参数
说明
推荐值
key
Cookie 名称
自定义
value
Cookie 值(字符串)
—
max_age
过期时间(秒),优先级高于 expires
按需
expires
具体的过期 datetime
—
path
生效路径,/ 表示全站
/
domain
生效域名,默认当前域
—
secure
仅 HTTPS 传输
True
httponly
禁止 JavaScript 访问
True
samesite
跨站请求控制:lax / strict / none
lax
安全提示 :生产环境务必开启 httponly、secure 和 samesite。httponly 能防止 XSS 窃取 Cookie,samesite=lax 能防御大部分 CSRF 攻击。
删除 Cookie 删除 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=0 和 expires=0,浏览器收到后就会删除该 Cookie。注意删除时的 path、domain 等参数必须和设置时一致,否则浏览器不会删除。
自定义 Response 中操作 Cookie 如果你的路由函数返回的不是简单字典,而是自定义 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, Requestfrom starlette.middleware.sessions import SessionMiddlewareapp = FastAPI() app.add_middleware( SessionMiddleware, secret_key="your-secret-key-change-in-production" , session_cookie="session_id" , max_age=3600 , same_site="lax" , https_only=False , ) @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 工作原理
读取请求 Cookie 中名为 session(或自定义名)的值
用 secret_key 验签并解密,还原为 Python 字典挂载到 request.session
路由函数可以像操作普通字典一样读写 request.session
响应时,中间件将 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, Cookiefrom starlette.middleware.sessions import SessionMiddlewarefrom typing import Optional app = FastAPI() app.add_middleware( SessionMiddleware, secret_key="super-secret-key-2026" , session_cookie="sid" , max_age=86400 , 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="用户名或密码错误" ) request.session["user" ] = username request.session["login_time" ] = "2026-07-19" response.set_cookie( key="remember_me" , value="1" , max_age=86400 * 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() response.delete_cookie("remember_me" ) return {"message" : "已退出登录" }
测试流程:POST /api/login → 浏览器自动保存 Cookie → GET /api/me 返回用户信息 → POST /api/logout 清除所有状态。
Cookie vs Session 对比
维度
Cookie
Session (Starlette)
数据存储位置
客户端浏览器
Cookie 中(加密签名)
容量限制
每个 Cookie 约 4KB
受 Cookie 总大小限制
安全性
明文,可被用户篡改
加密签名,篡改可检测
过期控制
max_age / expires
max_age(中间件参数)
适用场景
记住偏好、跟踪标识
登录态、用户数据
小结 Cookie 和 Session 是 Web 开发中管理用户状态的两大基石:
Cookie 适合存放轻量、非敏感的客户端标识,通过 set_cookie() 设置、Cookie() 读取
Session 通过 SessionMiddleware 实现,数据加密签名存储在 Cookie 中,适合存放登录态等需要防篡改的信息
安全是底线:生产环境务必启用 httponly、secure、samesite,且 secret_key 绝对不可泄露
掌握了 Cookie 和 Session,你就能构建出有”记忆”的 Web 应用——记住用户偏好、维护登录状态、实现购物车功能,全都离不开它们。