FastAPI 是一个现代、高性能的 Python Web 框架,基于 Starlette 和 Pydantic,支持异步编程。它提供了灵活的中间件机制,以及对 Session 和 Cookie 的内置支持,非常适合构建高效的 API 和 Web 应用。本文将详细介绍 FastAPI 的中间件、Session 和 Cookie 的使用方法,并通过实例代码进行说明。
1. FastAPI 中间件简介
中间件(Middleware)是 FastAPI 中用于在请求和响应之间执行额外逻辑的机制。它可以处理诸如日志记录、身份验证、请求修改等功能。FastAPI 的中间件基于 Starlette,采用异步方式运行。
1.1 中间件的工作原理
中间件本质上是一个在请求到达路由处理函数之前和响应返回客户端之后执行的函数。它通过 call_next(request) 调用下一个中间件或路由处理器,并可以修改请求或响应。
1.2 创建自定义中间件
以下是一个简单的中间件示例,用于记录请求的处理时间。
python
from fastapi import FastAPI, Request
import time
app = FastAPI()
# 自定义中间件
@app.middleware("http")
async def log_request_time(request: Request, call_next):
start_time = time.time()
response = await call_next(request) # 调用下一个中间件或路由
process_time = time.time() - start_time
print(f"请求路径: {request.url.path}, 处理时间: {process_time:.4f} 秒")
return response
@app.get("/")
async def root():
return {"message": "Hello, FastAPI!"}
说明:
- • @app.middleware("http") 装饰器定义了一个 HTTP 中间件。
- • request: Request 是传入的请求对象。
- • call_next 是异步函数,用于将请求传递给下一个处理环节。
- • 中间件在控制台打印请求路径和处理时间。
运行后,访问 http://127.0.0.1:8000/,你会在终端看到类似以下输出:
makefile
请求路径: /, 处理时间: 0.0012 秒
2. FastAPI 中的 Session
FastAPI 本身没有内置的 Session 管理,但可以通过第三方库(如 itsdangerous)或自定义实现来支持会话管理。Session 通常用于在多次请求之间存储用户状态。
2.1 使用 Cookie 实现 Session
以下是一个基于 Cookie 的简单 Session 实现:
python
from fastapi import FastAPI, Request, Response
from fastapi.responses import JSONResponse
import uuid
app = FastAPI()
# 模拟会话存储(实际应用中可以用数据库)
session_data = {}
@app.get("/set-session")
async def set_session(response: Response):
session_id = str(uuid.uuid4()) # 生成唯一会话 ID
session_data[session_id] = {"user": "test_user", "login_time": time.time()}
response.set_cookie(key="session_id", value=session_id, httponly=True)
return {"message": "Session 已设置", "session_id": session_id}
@app.get("/get-session")
async def get_session(request: Request):
session_id = request.cookies.get("session_id")
if session_id and session_id in session_data:
return {"session_data": session_data[session_id]}
return {"message": "未找到会话"}
说明:
- • /set-session 路由生成一个唯一的 session_id,存储在内存中的 session_data 字典,并通过 set_cookie 设置到客户端。
- • /get-session 路由从请求中获取 Cookie 的 session_id,并返回对应的会话数据。
- • httponly=True 确保 Cookie 只能通过 HTTP 访问,防止客户端脚本访问。
运行后:
-
- 访问 /set-session,浏览器会设置一个 session_id Cookie。
-
- 访问 /get-session,返回对应的会话信息。
3. FastAPI 中的 Cookie
Cookie 是客户端和服务器之间传递的小块数据,常用于身份验证、会话管理等。FastAPI 提供了简单的方法来设置和读取 Cookie。
3.1 设置 Cookie
通过 Response 对象的 set_cookie 方法可以设置 Cookie:
python
from fastapi import FastAPI, Response
app = FastAPI()
@app.get("/set-cookie")
async def set_cookie(response: Response):
response.set_cookie(key="user_id", value="12345", max_age=3600, httponly=True)
return {"message": "Cookie 已设置"}
参数说明:
- • key:Cookie 的名称。
- • value:Cookie 的值。
- • max_age:Cookie 的有效期(秒)。
- • httponly:防止客户端脚本访问。
3.2 读取 Cookie
通过 Request 对象的 cookies 属性读取 Cookie:
python
from fastapi import FastAPI, Request
app = FastAPI()
@app.get("/read-cookie")
async def read_cookie(request: Request):
user_id = request.cookies.get("user_id")
if user_id:
return {"user_id": user_id}
return {"message": "未找到 Cookie"}
运行后:
-
- 访问 /set-cookie,设置一个 user_id Cookie。
-
- 访问 /read-cookie,返回 {"user_id": "12345"}。
3.3 Cookie 与中间件结合
我们可以结合中间件检查 Cookie,实现简单的身份验证:
python
from fastapi import FastAPI, Request, HTTPException
from fastapi.responses import JSONResponse
app = FastAPI()
@app.middleware("http")
async def check_cookie(request: Request, call_next):
if request.url.path.startswith("/protected"):
user_id = request.cookies.get("user_id")
if not user_id:
return JSONResponse(status_code=403, content={"message": "需要登录"})
response = await call_next(request)
return response
@app.get("/protected/data")
async def protected_data():
return {"message": "这是受保护的数据"}
说明:
- • 中间件检查请求路径是否以 /protected 开头,并验证是否存在 user_id Cookie。
- • 如果没有 Cookie,返回 403 错误。
4. 综合实例:用户登录系统
以下是一个结合中间件、Session 和 Cookie 的完整示例,模拟用户登录系统:
python
from fastapi import FastAPI, Request, Response, HTTPException
from fastapi.responses import JSONResponse
import uuid
import time
app = FastAPI()
session_data = {}
# 中间件:检查登录状态
@app.middleware("http")
async def auth_middleware(request: Request, call_next):
if request.url.path.startswith("/api"):
session_id = request.cookies.get("session_id")
if not session_id or session_id not in session_data:
return JSONResponse(status_code=401, content={"message": "未登录"})
response = await call_next(request)
return response
# 登录路由
@app.post("/login")
async def login(response: Response):
session_id = str(uuid.uuid4())
session_data[session_id] = {"user": "admin", "login_time": time.time()}
response.set_cookie(key="session_id", value=session_id, httponly=True, max_age=3600)
return {"message": "登录成功"}
# 受保护的 API
@app.get("/api/user")
async def get_user(request: Request):
session_id = request.cookies.get("session_id")
return {"user": session_data[session_id]["user"]}
# 退出登录
@app.post("/logout")
async def logout(request: Request, response: Response):
session_id = request.cookies.get("session_id")
if session_id in session_data:
del session_data[session_id]
response.delete_cookie("session_id")
return {"message": "已退出登录"}
运行流程:
-
- 访问 /login,设置 session_id Cookie 并保存会话。
-
- 访问 /api/user,中间件验证 Cookie,返回用户信息。
-
- 访问 /logout,删除会话和 Cookie。
4. 总结
FastAPI 的中间件、Session 和 Cookie 提供了强大的工具来处理请求和用户状态:
- • 中间件:适合全局逻辑,如日志、身份验证。
- • Session:通过 Cookie 或数据库实现状态管理。
- • Cookie:用于在客户端和服务器之间传递数据。