FastAPI的中间件定义的三种方式
中间件相当于是请求/响应拦截器,可以在请求进入路由处理之前,以及响应返回给客户之前,执行一些全局的处理逻辑。
如可以在中间件中做如下的事情:
- 鉴权/权限检查
- 记录访问日志
- 请求数据预处理(JSON解码,Header检查等)
- 接口限流
- 黑名单拦截
中间件定义方式
1.装饰器模式(@app.middleware('http'))
这是FastApi官方推荐的简单方式,适合写轻量级的中间件
from fastapi import FastAPI, Request
import time
app = FastAPI()
@app.middleware("http")
async def log_requests(request: Request, call_next):
start_time = time.time()
# 请求前逻辑
print(f"请求: {request.method} {request.url}")
# 调用下一个中间件 / 路由处理
response = await call_next(request)
# 请求后逻辑
process_time = time.time() - start_time
response.headers["X-Process-Time"] = str(process_time)
return response
特点:
- 简单直观,适合小型小米或者少量中间件
- 只能拦截HTTP请求
- 不适合复杂依赖注入和跨多类型请求(如webSocket)
2.类继承方式(BaseHTTPMiddleware)
来自 starlette.middleware.base.BaseHTTPMiddleware,适合封装成可复用的中间件类。
from fastapi import FastAPI, Request
from starlette.middleware.base import BaseHTTPMiddleware
import time
class TimerMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
response.headers["X-Process-Time"] = str(process_time)
return response
app = FastAPI()
app.add_middleware(TimerMiddleware)
特点:
- 结构清晰,方便封装和复用
- 支持通过app.add_middleware传参数
- 更容易与第三方库或框架的中间件机制集成
3.ASGI原生中间件
这种方式是写的一个符合ASGI规范的函数或类, 能拦截所有类型的请求(http, WebSocket,lifespan)
class ASGIMiddleware:
def __init__(self, app):
self.app = app
async def __call__(self, scope, receive, send):
print(f"收到请求类型: {scope['type']}")
await self.app(scope, receive, send)
app = FastAPI()
# app = ASGIMiddleware(app)
app.add_middleware(ASGIMiddleware, app)
特点:
- 直接操作ASGI事件循环
- 可同时处理多种类型的请求
- 适合需要完全控制协议层的情况
- 对初学者不太友好
中间件的注册顺序和执行顺序
- 请求阶段:后注册的先执行
- 响应阶段:先注册的后返回
- 最先注册 → 最后进入请求流程
- 最后注册 → 最先进入请求流程
性能问题
使用中间件会影响部分性能,每种定义方式性能略有差别,我简单测试了一下,发现 ASGI方式 > 装饰器方式 > 继承方式。
FastAPI的中间件定义的三种方式
https://www.diaoyc.cn//archives/fastapi_middleware_3