什么是中间件

在构建 Web 应用时,我们常常需要处理诸如日志记录、请求验证、响应压缩等通用任务。如果每次都在每个路由函数中重复编写这些代码,不仅会导致代码冗余,还会使代码难以维护和扩展。FastAPI 中的中间件(Middleware)机制为解决这些问题提供了优雅的方案,它可以在请求到达路由之前和响应返回给客户端之前,对请求和响应进行统一处理,极大地提升了 Web 应用的灵活性与效率

中间件就像是 Web 应用的 "门卫" 和 "质检员",它位于客户端请求与应用路由之间,以及应用路由与客户端响应之间。当客户端发送一个请求时,请求会按照顺序依次经过各个中间件,每个中间件可以对请求进行处理、修改或添加信息。处理完请求后,响应又会以相反的顺序再次经过中间件,中间件可以对响应进行调整,比如添加响应头、压缩响应体等。通过中间件,我们能够将一些通用的逻辑从路由函数中分离出来,实现代码的复用和模块化

为什么使用中间件

  1. 代码复用:将通用逻辑(如身份验证、日志记录)封装在中间件中,避免在多个路由函数中重复编写相同代码。​
  2. 集中管理:所有中间件都在一个地方注册和配置,方便对这些通用功能进行统一管理和修改。​
  3. 提高可维护性:当需要修改某个通用功能时,只需要在中间件中进行修改,而无需逐一修改每个路由函数。​
  4. 增强扩展性:可以根据需求灵活添加或移除中间件,轻松扩展应用的功能。

FastAPI 中间件的基本使用

在 FastAPI 中使用中间件非常简单,只需要通过app.add_middleware()方法将中间件添加到 FastAPI 应用实例中。下面是一个简单的示例,展示如何创建一个自定义中间件来记录请求的开始和结束时间:

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
import time

app = FastAPI()

# 自定义中间件
@app.middleware("http")
async def add_process_time_header(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

# 添加CORS中间件
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.get("/")
async def root():
    return {"message": "Hello World"}

在上述代码中:

  1. 首先定义了一个 FastAPI 应用实例app
  2. 使用@app.middleware("http")装饰器创建了一个自定义的 HTTP
    中间件add_process_time_header。在这个中间件中,记录了请求开始的时间,然后调用call_next(request)将请求传递给下一个中间件或路由函数,获取响应后,计算请求处理的时间,并将其添加到响应头中
  3. 使用app.add_middleware()方法添加了一个CORSMiddleware,用于处理跨域资源共享(CORS)问题,允许所有来源、所有方法和所有头部的请求
  4. 最后定义了一个根路由/,当访问该路由时,返回一个包含 "Hello World" 消息的 JSON 响应

常用的 FastAPI 中间件

CORS 中间件

在现代 Web 开发中,由于浏览器的同源策略限制,当 Web 应用从不同的域名、端口或协议请求资源时,会出现跨域问题。FastAPI 的CORSMiddleware可以轻松解决这个问题。通过配置allow_originsallow_methodsallow_headers等参数,可以精确控制哪些来源、方法和头部的请求被允许

app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://example.com"],  # 允许的来源
    allow_credentials=True,
    allow_methods=["GET", "POST"],  # 允许的HTTP方法
    allow_headers=["Content-Type"],  # 允许的请求头部
)

GZip 中间件

GZip 中间件用于对响应进行压缩,减少数据传输量,提高应用的性能。特别是对于传输较大数据的 API 接口,使用 GZip 压缩可以显著加快响应速度

from fastapi.middleware.gzip import GZipMiddleware

app.add_middleware(
    GZipMiddleware,
    minimum_size=1000  # 只有当响应体大小超过1000字节时才进行压缩
)

身份验证中间件

在实际应用中,很多接口需要进行身份验证,确保只有合法用户才能访问。可以创建一个自定义的身份验证中间件,在请求到达路由之前验证用户的身份信息。例如,验证请求头中的 JWT 令牌:

from fastapi import Request, HTTPException
from fastapi.responses import JSONResponse
import jwt

# 自定义身份验证中间件
@app.middleware("http")
async def authenticate(request: Request, call_next):
    token = request.headers.get("Authorization")
    if not token:
        raise HTTPException(status_code=401, detail="Unauthorized")
    try:
        payload = jwt.decode(token.split(" ")[1], "secret_key", algorithms=["HS256"])
        request.state.user = payload  # 将用户信息存储在请求对象中,供路由函数使用
    except jwt.PyJWTError:
        raise HTTPException(status_code=401, detail="Invalid token")
    response = await call_next(request)
    return response

中间件的执行顺序

中间件的执行顺序非常重要,因为请求和响应会按照中间件注册的顺序依次经过它们。当添加中间件时,先注册的中间件会先处理请求,后注册的中间件后处理请求;而在响应阶段,顺序则相反,后注册的中间件先处理响应,先注册的中间件后处理响应。因此,在设计中间件时,需要根据功能的依赖关系合理安排中间件的注册顺序

最后修改:2025 年 06 月 08 日
如果觉得我的文章对你有用,请随意赞赏