文章目录
- 前言
- 一、什么是中间件
-
- 1.1什么是中间件
- [1.2 中间件的原理](#1.2 中间件的原理)
- [1.3 如何实现中间件](#1.3 如何实现中间件)
- [1.4 多中间件的执行流程](#1.4 多中间件的执行流程)
- 二、依赖系统
-
- [2.1 什么是依赖系统,为什么要用依赖系统?](#2.1 什么是依赖系统,为什么要用依赖系统?)
- [2.2 如何实现依赖系统](#2.2 如何实现依赖系统)
- 结语
前言
代码的优雅在于复用,架构的精妙在于分层。中间件让你掌控请求的必经之路,依赖系统让你告别重复代码。本文从拦截器模式出发,详解FastAPI两大核心机制,助你写出更干净、更可维护的后端代码。
一、什么是中间件
1.1什么是中间件
中间件是插在用户请求和API之间的一道关卡。用户的请求想要到达API,必须先经过中间件。中间件可以检查请求、修改请求,甚至直接拒绝请求。

在图片中当用户发送request请求后,会先经过m1和m2两个中间件,然后才能到达API。中间件还可以把数据发送到消息队列,或者执行定时任务。
中间件的实际应用场景包括:
-
鉴权:判断用户是否登录
- 认证:验证用户身份
- 授权:判断用户有没有权限做某个操作
-
记录日志
-
数据清洗:检查数据是否合法
-
限流:控制请求频率,防止服务器被压垮
...
1.2 中间件的原理
中间件本质上是一个拦截器。它利用了设计模式中的拦截器模式。

中间件的执行流程如下:
- 请求到达中间件
- 中间件在请求向下传递之前执行一些动作
- 调用
await call_next(request)把请求传给下一个环节 - API处理完请求后,响应会原路返回
- 中间件在请求返回之后还可以执行一些动作
这就像你去电影院看电影:
- 你先到检票口(中间件),检票员检查你的票
- 票没问题,你进入影厅(API)
- 看完电影,你原路返回,检票员还可以记录你的离场时间
1.3 如何实现中间件
在FAstAPI中,使用@app.middleware("http")装饰器来创建中间件。
python
from fastapi import FastAPI, Request
app = FastAPI()
@app.middleware("http")
async def m1(request: Request, call_next):
"""
中间件1
:param request: 请求对象,包含用户请求的所有信息
:param call_next: 将请求继续向下传递的函数
:return: 响应对象
"""
# 请求向下传递之前执行的动作
print("中间件1请求向下传递之前执行了动作")
# 将请求继续向下传递,await表示等待后续处理完成
response = await call_next(request)
# 请求返回之后执行的动作
print("中间件1请求向下传递之后执行了动作")
return response
代码详解:
request参数是用户的请求对象,可以读取请求头、Cookie等信息call_next是一个函数,调用它会把请求传给下一个中间件或APIawait call_next(request)是异步调用,等待后续处理完成- 中间件必须在最后返回
response对象
1.4 多中间件的执行流程
当存在多个中间件时,它们的执行顺序是特殊的。
python
from fastapi import FastAPI, Request
app = FastAPI()
@app.middleware("http")
async def m1(request: Request, call_next):
print("中间件1请求向下传递之前执行了动作")
response = await call_next(request)
print("中间件1请求向下传递之后执行了动作")
return response
@app.middleware("http")
async def m2(request: Request, call_next):
print("中间件2请求向下传递之前执行了动作")
response = await call_next(request)
print("中间件2请求向下传递之后执行了动作")
return response
执行顺序如下:
- 请求先到达m1,打印"中间件1请求向下传递之前执行了动作"
- m1调用call_next,请求进入m2
- m2打印"中间件2请求向下传递之前执行了动作"
- m2调用call_next,请求到达API
- API处理完,响应返回给m2
- m2打印"中间件2请求向下传递之后执行了动作"
- 响应返回给m1
- m1打印"中间件1请求向下传递之后执行了动作"
总结:多个中间件的执行顺序是"先下后上"。请求下去时先经过m1再到m2,返回时先经过m2再到m1。
这就像套娃,一层一层进去,再一层一层出来。
注意事项:
- 中间件一旦建立,项目中所有的路由都会经过它
- 但是可以通过判断URL路径,让某些路由走不同的逻辑
二、依赖系统
2.1 什么是依赖系统,为什么要用依赖系统?
在实际开发中,很多API需要重复执行相同的代码。比如用户管理、订单管理、会员管理这三个模块,都需要做做分页查询。每个模块都需要获取offset和limit参数,都要根据这两个参数查询数据库。但是这些模块的代码几乎是一样的。如果每个模块都写一遍,代码就会很冗余。
依赖系统就是为了解决这个问题。它把公共的代码抽成一个函数,然后在多个路由中重复使用。
依赖系统的核心思想是:
- 复用:减少重复代码
- 注入:把公共功能以参数的形式注入到路由函数中
2.2 如何实现依赖系统
实现依赖系统分为两步:
- 创建一个普通函数,这个函数就是依赖
- 在路由函数中使用
Depends注入这个依赖
python
from fastapi import APIRouter, Depends
from fastapi.params import Query
dependency_router = APIRouter()
# 第一步:创建依赖系统(这是一个普通的函数)
async def common_page(
offset: int = Query(0, description="分页偏移量"),
limit: int = Query(10, description="分页数量")
):
"""
这个函数接收分页参数,返回分页信息
它可以在多个路由中重复使用
"""
return {
"offset": offset,
"limit": limit
}
# 第二步:在路由中使用Depends注入依赖
@dependency_router.get("/page/")
async def get_user_page_list(common = Depends(common_page)):
"""
common参数会自动接收common_page函数的返回值
"""
print(common) # 打印: {'offset': 0, 'limit': 10}
return {
"message": "获取用户分页列表成功"
}
代码详解:
common_page是一个普通函数,它接收offset和limit两个查询参数Query(0,description="分页偏移量")表示这是一个查询参数,默认值是0Depends(common_page)告诉FAstAPI:先执行common_page函数,把它的返回值传给common参数- 这样get_user_page_list函数就能直接拿到分页参数,不需要自己解析
依赖系统的好处:
- 代码简洁:不需要在每个路由中都写参数解析
- 逻辑更清晰:公共逻辑抽离出来,便于维护
- 易于测试:依赖函数可以单独测试
更复杂的例子:
可以在依赖函数中做更多事情,比如数据库连接、权限检查等:
python
from fastapi import APIRouter, Depends, HTTPException
dependency_router = APIRouter()
# 模拟数据库连接
async def get_db():
db = "数据库连接对象"
return db
# 模拟权限检查
async def check_permission(db = Depends(get_db)):
# 检查用户是否有权限
has_permission = True
if not has_permission:
raise HTTPException(status_code=403, detail="没有权限")
return db
# 使用多个依赖
@dependency_router.get("/data/")
async def get_data(
db = Depends(get_db),
perm = Depends(check_permission)
):
# 这里可以直接使用数据库连接,因为权限检查已经通过了
return {"message": "获取数据成功"}
在这个例子中,check_permission依赖又依赖于get_db。FastAPI会自动处理这种依赖链。
结语
中间件是守门人,依赖系统是组装线。掌握它们,你就掌握了代码复用的精髓。把这些模式用熟,你的项目会少一半重复代码,多一倍清晰逻辑。继续写代码,继续优化,我们下篇再见。