在构建现代 Web 应用时,我们通常需要处理一些请求和响应的共同逻辑,比如请求的预处理、响应的后处理、错误处理、身份验证、日志记录等。中间件正是 FastAPI 提供的功能,用来处理这些跨多个路由的通用任务。
本文将介绍 FastAPI 中的 中间件,并帮助你理解它的工作原理、使用场景以及如何利用它来处理请求和响应。
1. 什么是中间件?它如何工作?
1.1 中间件定义
在 FastAPI 中,中间件是一个在请求和响应的生命周期中间插入的组件。它允许你在请求到达路由处理之前和响应返回给客户端之前执行一些额外的操作。中间件不仅能够处理请求,还能够修改响应或者对请求和响应执行其他操作。
简单来说,中间件是一个功能扩展,它能在请求生命周期的不同阶段对数据进行操作。例如:
- 在请求到达路由之前:对请求进行验证、日志记录、添加请求头等。
- 在响应返回客户端之前:对响应内容进行修改、添加响应头、记录响应时间等。
1.2 中间件的工作流程
FastAPI 中间件的工作流程大致如下:
- 请求到达应用:当一个 HTTP 请求到达 FastAPI 应用时,它首先经过中间件。
- 中间件处理请求:中间件可以选择处理请求,或将请求传递给下一个中间件。
- 路由处理请求:当请求通过所有中间件后,FastAPI 会调用相应的路由处理函数来处理这个请求。
- 响应生成:路由处理函数生成响应后,它会再次经过中间件,可以在此阶段修改响应或执行其他操作。
- 响应返回客户端:经过所有中间件处理后,响应最终返回给客户端。
1.3 中间件与路由的区别
- 中间件:通常处理一些跨路由的任务,如请求的验证、日志记录、全局异常处理等。
- 路由:专门处理某个特定的 HTTP 请求,并返回相应的业务逻辑结果。
1.4 FastAPI 中间件的基础结构
在 FastAPI 中,所有的中间件都需要继承自 BaseHTTPMiddleware
类,并实现 dispatch
方法。dispatch
方法接收两个参数:
request
:请求对象。call_next
:用于继续调用下一个中间件或者最终的路由处理函数。
返回的响应将经过中间件的后处理,然后返回给客户端。
2. 如何使用中间件处理请求和响应
2.1 创建自定义中间件
下面是一个简单的自定义中间件示例,演示如何在请求到达路由之前记录请求的日志,或者在响应返回之前添加一些响应头。
from fastapi import FastAPI
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.responses import JSONResponse
import logging
app = FastAPI()
# 设置日志记录
logging.basicConfig(level=logging.INFO)
# 创建自定义中间件
class RequestResponseLoggingMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request, call_next):
# 请求到达时的处理
logging.info(f"Request: {request.method} {request.url}")
# 继续处理请求,直到路由处理函数
response = await call_next(request)
# 响应返回时的处理
logging.info(f"Response: {response.status_code}")
# 可以对响应做进一步处理,例如添加自定义的响应头
response.headers['X-Custom-Header'] = 'MyCustomHeader'
return response
# 注册自定义中间件
app.add_middleware(RequestResponseLoggingMiddleware)
@app.get("/items/{item_id}")
async def read_item(item_id: int):
return {"item_id": item_id}
代码解析:
RequestResponseLoggingMiddleware
类继承了BaseHTTPMiddleware
,重写了dispatch
方法。dispatch
方法的作用是:在请求到达路由之前执行一些操作(如日志记录请求),然后通过call_next(request)
将请求传递给下一个中间件或路由处理函数。- 路由处理完请求后,响应会经过该中间件,再次执行后处理操作(如记录响应状态码、添加自定义头等)。
2.2 注册中间件
在 FastAPI 中,使用 app.add_middleware()
方法来注册中间件。
app.add_middleware(RequestResponseLoggingMiddleware)
通过调用这个方法,我们将 RequestResponseLoggingMiddleware
中间件添加到 FastAPI 应用中,使它能够处理所有传入的请求和响应。
2.3 访问请求和响应对象
在中间件的 dispatch
方法中,我们可以访问请求对象 request
,这个对象包含了 HTTP 请求的所有信息,例如请求方法(GET、POST等)、请求路径、查询参数、请求头等。
request.method # 请求方法,例如 "GET" 或 "POST"
request.url # 请求的完整 URL,包括协议、主机、路径和查询参数
同时,我们还可以修改响应对象 response
,比如为响应添加自定义的 HTTP 头或更改响应的内容。
response.headers['X-Custom-Header'] = 'CustomValue' # 向响应添加自定义头
2.4 使用中间件处理跨域资源共享(CORS)
一个常见的应用场景是处理跨域资源共享(CORS)。FastAPI 提供了 CORSMiddleware
来帮助我们处理 CORS 问题。我们可以直接在应用中注册这个中间件:
from fastapi.middleware.cors import CORSMiddleware
# 允许所有域名跨域访问
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # 可以指定允许的来源
allow_credentials=True,
allow_methods=["*"], # 可以允许所有的 HTTP 方法
allow_headers=["*"], # 可以允许所有的请求头
)
CORSMiddleware
使得跨域请求变得更加方便,它会在响应中添加必要的 CORS 头(如 Access-Control-Allow-Origin
),从而允许不同来源的客户端访问服务器的资源。
2.5 使用中间件进行身份验证
另一个常见的应用场景是身份验证。我们可以使用中间件在请求到达路由之前进行身份验证,确保只有经过身份验证的用户能够访问某些 API:
from fastapi import HTTPException
from starlette.middleware.base import BaseHTTPMiddleware
class AuthMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request, call_next):
# 获取请求头中的认证信息
auth_header = request.headers.get("Authorization")
if not auth_header or auth_header != "Bearer my-secret-token":
raise HTTPException(status_code=401, detail="Unauthorized")
# 如果认证通过,继续处理请求
response = await call_next(request)
return response
# 注册身份验证中间件
app.add_middleware(AuthMiddleware)
在这个例子中,AuthMiddleware
会检查每个请求的 Authorization
头,确保它包含正确的认证信息。如果认证失败,它会抛出 HTTPException
并返回 401 错误;如果认证通过,请求将继续传递给后续的处理函数。
3. 总结
中间件是 FastAPI 中处理请求和响应的一种强大工具。通过中间件,我们可以在请求生命周期的各个阶段执行逻辑,从而实现:
- 请求和响应的预处理和后处理(如日志记录、响应修改等)。
- 统一处理跨多个路由的任务(如身份验证、CORS、错误处理等)。
- 增加代码的可维护性和模块化。
FastAPI 提供了便捷的 API 来创建和注册中间件,让我们能够高效地处理应用的跨路由功能。在开发复杂的 Web 应用时,合理使用中间件能够大大提升代码的清晰度和可维护性。
邀请您关注公众号,感谢