在FastAPI中,中间件(Middleware)是一种非常实用的功能,它允许我们在请求到达视图函数之前和响应返回给客户端之后,统一处理一些逻辑,比如认证、日志记录、错误处理等。本文将通过一个实战案例,带你实现一个简单的中间件,用于记录请求日志和统计响应时间,让你的API开发更规范、更便于调试。
一、环境准备¶
首先,确保你已经安装了FastAPI和Uvicorn(用于运行FastAPI应用的服务器)。如果还没有安装,可以通过以下命令安装:
pip install fastapi uvicorn
二、中间件的作用¶
为什么要使用中间件来做请求日志和响应时间统计呢?想象一下,如果我们在每个视图函数里都手动记录这些信息,会产生大量重复代码,而且一旦需求变化(比如要新增字段),修改起来也会很麻烦。中间件可以帮我们统一处理这些逻辑,所有请求都会自动经过中间件,既简洁又易于维护。
三、编写中间件实现请求日志与响应时间统计¶
我们需要创建一个中间件类,继承Starlette提供的BaseHTTPMiddleware(FastAPI基于Starlette开发,所以中间件逻辑由Starlette管理),并在dispatch方法中实现日志记录和时间统计的逻辑。
1. 定义中间件类¶
from fastapi import FastAPI
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
import time
class LoggingMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
# 记录请求开始时间(使用time模块获取当前时间戳)
start_time = time.time()
# 调用下一个中间件或视图函数,获取响应
response = await call_next(request)
# 计算响应耗时(结束时间 - 开始时间)
duration = time.time() - start_time
# 构造日志信息
log_info = (
f"[请求日志] 方法: {request.method} | "
f"路径: {request.url.path} | "
f"客户端IP: {request.client.host} | "
f"耗时: {duration:.4f}秒 | "
f"状态码: {response.status_code}"
)
# 打印日志(实际项目中可替换为logging模块输出到文件)
print(log_info)
return response
2. 解释中间件逻辑¶
- 继承
BaseHTTPMiddleware:这是Starlette提供的中间件基类,封装了中间件的基本处理流程,我们只需实现dispatch方法即可。 dispatch方法:这是中间件的核心方法,接收两个参数:request:当前请求对象(包含请求方法、路径、客户端信息等)。call_next:一个异步函数,用于调用下一个中间件或视图函数,返回处理后的响应。- 时间统计:在请求处理前记录开始时间,处理完成后记录结束时间,计算时间差(
duration)。 - 日志构造:将请求方法、路径、客户端IP、耗时、响应状态码等信息整合为一条日志,方便查看和调试。
四、添加中间件到FastAPI应用¶
创建FastAPI应用后,通过add_middleware方法将我们定义的中间件添加到应用中:
# 创建FastAPI应用实例
app = FastAPI()
# 添加中间件(全局生效)
app.add_middleware(LoggingMiddleware)
五、测试中间件效果¶
接下来,我们定义几个简单的视图函数,测试中间件是否能正确记录请求日志和响应时间。
1. 定义测试路由¶
@app.get("/")
async def root():
return {"message": "Hello, FastAPI!"}
@app.get("/items/{item_id}")
async def read_item(item_id: int):
return {"item_id": item_id, "item_name": f"Item {item_id}"}
@app.post("/users")
async def create_user(name: str):
return {"user": {"name": name, "status": "created"}}
2. 运行应用并测试¶
在终端执行以下命令启动应用:
uvicorn main:app --reload
此时,访问不同的接口(例如http://localhost:8000/、http://localhost:8000/items/123、http://localhost:8000/users?name=test),观察控制台输出的日志。
3. 日志输出示例¶
访问http://localhost:8000/后,控制台可能输出类似以下内容:
[请求日志] 方法: GET | 路径: / | 客户端IP: 127.0.0.1 | 耗时: 0.0002秒 | 状态码: 200
六、扩展与优化¶
以上是最基础的中间件实现,你可以根据实际需求进行扩展:
- 使用
logging模块:将print替换为Python的logging模块,支持日志分级(INFO/WARNING/ERROR)、输出到文件等。 - 记录请求体:对于POST/PUT请求,可以通过
await request.json()获取请求数据(注意敏感信息脱敏)。 - 异常处理:在中间件中捕获视图函数抛出的异常,记录错误堆栈信息。
- 处理跨域:如果需要跨域支持,可以添加CORS中间件。
总结¶
通过本文,你学习了如何使用FastAPI中间件统一实现请求日志和响应时间统计,避免了重复代码,提高了代码的可维护性。中间件是FastAPI(以及Starlette)中处理请求/响应前置和后置逻辑的强大工具,后续可以尝试将更多通用逻辑(如认证、跨域处理)封装到中间件中,让API开发更高效、规范。