06. FastAPI——中间件

一、什么是中间件?

实际中的请求流程都不是直接到自己写的接口函数的,而是:

复制代码
客户端 → 中间件 → 路由函数 → 中间件 → 客户端

中间件其实是在**"请求到达接口之前"** 和**"响应返回客户端之前"** 执行的一段公共代码, 就像一个拦截器 / 关卡 / 过滤器。可以把中间件看作放公共逻辑的地方,这样避免有些需要重复执行的逻辑在每个接口都写一遍。

其常见应用场景如下:

用途 举例
日志记录 记录谁访问了哪个接口
身份认证 判断用户是否登录
统计接口耗时 看接口慢不慢
统一异常处理 捕获全局异常
跨域处理 允许前端访问
请求限流 防止接口被刷
统一添加响应头 加 token / 加版本号
[中间件常见用途]

根据文章开头的实际请求流程,可以看出中间件可以做两件事:

复制代码
1. 请求进入前处理 request
2. 响应返回前处理 response

二、中间件代码示例

在实际代码中,如何定义中间件?具体运行方式又如何?

1、写出一个中间件

FastAPI 中间件有两种写法:装饰器写法类中间件写法

写法 类比
装饰器写法(@app.middleware) 小脚本
类中间件写法(BaseHTTPMiddleware) 正式模块

当前只需要掌握装饰器写法即可。代码示例:

python 复制代码
from fastapi import FastAPI

app= FastAPI()

# 利用装饰器来定义中间件,不论几个中间件装饰器@app.middleware("http")的写法是固定的
@app.middleware("http")
'''这里开始定义中间件函数的具体内容
   request是请求
   call_next是FastAPI在执行中间件时自动传进来的一个函数'''

# 根据中间件的用途定义中间件函数名称
async def log_middleware(request, call_next):
    print("有人访问了:", request.url)

    # call_next()让请求继续往后走,交给真正的接口函数处理,然后把接口函数的返回值拿回来
    response = await call_next(request)

    print("请求处理完成")
    return response

@app.get("/")
async def root():
    print('这里是root函数')
    return {"message": "hello world"}

运行效果如下:

关于中间件的核心代码其实只有:

python 复制代码
async def log_middleware(request, call_next):
    ...
    response = await call_next(request)
    ...

'''
其中:
request 是fastapi自动创建的Request的实例对象。
        其标准写法应该是:async def log_middleware(request:Request, call_next):

call_next 是 FastAPI 在执行中间件时提供的一个函数。不需要自己创建,直接在中间件模块里调用即可。
          其作用是把请求继续传递给下一个中间件或路由函数处理,并返回响应结果。

await 是Python异步处理的关键字。
      它表示call_next()函数异步执行。
'''

2、中间件的洋葱式运行顺序

可以看到当单个中间件执行的时候,代码的运行顺序是:

python 复制代码
middleware1 → root()函数 → middleware1

相当于 root 函数被嵌套在了 middleware1 里面了。

当定义两个中间件时,示例代码:

python 复制代码
from fastapi import FastAPI

app = FastAPI()

# 中间件1
@app.middleware("http")
async def middleware1(request, call_next):
    print("中间件1:响应前")
    response = await call_next(request)
    print("中间件1:响应后")
    return response

# 中间件2
@app.middleware("http")
async def middleware2(request, call_next):
    print("中间件2:响应前")
    response = await call_next(request)
    print("中间件2:响应后")
    return response

@app.get("/")
async def root():
    print("这里是root函数")
    return {"message": "hello"}

通过两个中间件的示例,可以更清楚地看到其按照洋葱式顺序执行:

python 复制代码
中间件2 → 中间件1 → root()函数 → 中间件1 → 中间件2

多个中间件和路由函数嵌套起来了:middleware2 ( middleware1 ( root函数 ) )


三、3个中间件的实际代码示例

仅凭借阅读概念和简单的示例代码可能无法立刻理解中间件,需要结合实际场景多写代码才能加深理解。此处用3个例子初步加深印象。

1、例子1:打印所有访问的URL(日志中间件)

python 复制代码
from fastapi import FastAPI, Request

app = FastAPI()

@app.middleware("http")
async def log_middleware(request: Request, call_next):
print("有人访问了:", request.url)

response = await call_next(request)

print("请求处理完成")
return response

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

访问浏览器时,会看到终端打印:

python 复制代码
有人访问了: http://127.0.0.1:8000/
请求处理完成

这就是最简单的日志中间件

2、例子2:统计接口耗时 / 性能监控(非常常见)

python 复制代码
from fastapi import FastAPI, Request
import time

app = FastAPI()

@app.middleware("http")
async def time_middleware(request: Request, call_next):
start = time.time()

response = await call_next(request)

end = time.time()
print("接口耗时:", end - start)

return response

@app.get("/slow")
async def slow_api():
time.sleep(1)
return {"msg": "slow api"}

访问 /slow,终端会显示:

python 复制代码
接口耗时: 1.00

3、例子3:简单"登录检查"(认证中间件思想)

python 复制代码
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse

app = FastAPI()

@app.middleware("http")
async def auth_middleware(request: Request, call_next):
token = request.headers.get("token")

if token != "123":
return JSONResponse(
    status_code=401,
    content={"error": "未登录"}
)

response = await call_next(request)
return response

@app.get("/user")
async def user():
return {"name": "alex"}

现在你访问:http://127.0.0.1:8000/user

会返回:

python 复制代码
{"error": "未登录"}

只有在请求头里加:token: 123,才能访问。

相关推荐
Datacarts2 小时前
亚马逊爆款选品:数据采集与三方服务商对接
开发语言·人工智能·python·信息可视化
IronMurphy2 小时前
Java 泛型深度解析:编译期类型擦除机制与 PECS 准则
java·windows·python
Roselind_Yi2 小时前
多模态数据挖掘前沿:生物医学与情感分析领域论文深度解析
人工智能·python·数据挖掘·nlp·gnn·情感分析·loss
wuqingshun3141592 小时前
说一下spring的bean的作用域
java·后端·spring
小羊羔heihei2 小时前
Python编程实战:12道趣味算法题
笔记·python·学习·其他·算法·学习方法·交友
南 阳2 小时前
Python从入门到精通day59
开发语言·python·php
JMchen1232 小时前
Android NDK开发从入门到实战:解锁应用性能的终极武器
android·开发语言·c++·python·c#·android studio·ndk开发
weixin_457760002 小时前
深入解析 Beam Search:从原理到实践的高效解码算法
python·算法
钟智强3 小时前
从2.7GB到481MB:我的Docker Compose优化实战,以及为什么不能全信AI
后端·docker