0. 一句话定位
| 维度 | 内容 |
|---|---|
| 作用对象 | 函数(ASGI 中间件 callable) |
| 使用场景 | 中间件 |
| 来源 | fastapi / starlette |
| 语法形式 | @app.middleware("http") 或 app.add_middleware(...) |
1. 做什么
在路由匹配之前/之后包裹每个 HTTP 请求:可记录日志、加响应头、鉴权、计时;通过 call_next(request) 把请求交给内层(最终到端点),再处理返回的 Response。
2. 重点参数
@app.middleware("http")
| 参数 | 类型 | 作用 | 配置建议 |
|---|---|---|---|
| 被装饰函数 | async fn | 签名为 (request, call_next) |
必须 async |
call_next |
callable | 调用下一层,返回 Response | 不 await 则响应断链 |
app.add_middleware(cls, **options)
| 参数 | 类型 | 作用 | 配置建议 |
|---|---|---|---|
| 中间件类 | ASGI Middleware | 如 CORSMiddleware |
后添加的通常更靠外 |
| 选项 | kwargs | 如 allow_origins |
见各类文档 |
3. 最小可运行示例
装饰器式 HTTP 中间件
1 | import time |
类中间件(CORS)
1 | from fastapi.middleware.cors import CORSMiddleware |
4. 常见变体
请求 ID 日志
1 | import uuid |
短路(不进入路由)
1 | from fastapi.responses import JSONResponse |
5. 适用 / 不适用
适用
- 全路径日志、计时、CORS、GZip、统一错误包装
- 与具体业务参数无关的横切逻辑
不适用
- 需要注入 DB/用户到端点 →
Depends - 仅个别路由鉴权 → 路由级
dependencies=[Depends(...)] - 进程启动级初始化 →
lifespan上下文
6. 易踩坑
- 中间件必须
returnResponse;忘记await call_next导致挂起 - 洋葱模型:后
add_middleware的请求阶段更靠外;调试顺序时画层图 - 中间件内读
request.body()会消耗 body,影响后续端点,需缓存技巧 - 同步阻塞操作会拖慢所有请求
7. 近邻替代
| 替代 | 何时用 |
|---|---|
Depends |
按路由注入依赖 |
@app.exception_handler |
异常转响应 |
| 反向代理(nginx) | TLS、限流、静态文件 |