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,才能访问。

相关推荐
Samooyou5 小时前
RAG项目案例--02在线检索&过滤流水线
人工智能·python·ai·全文检索·检索
动能小子ohhh5 小时前
DocForge平台的设计与开发--文件上传接口的实现
开发语言·人工智能·python·langchain·ocr·fastapi
ab_dg_dp5 小时前
Android 17+ 提取 AIDL 生成 Java 文件的实用脚本
android·java·python
小村儿6 小时前
连载13- 内部Tools,Claude Code 怎么真正"动"你的代码
前端·后端·ai编程
IT_陈寒6 小时前
Python的线程池把我坑惨了,原来异步不是万能的
前端·人工智能·后端
夏语灬6 小时前
cryptography:Python 密码学标准库的终极选择
开发语言·python·密码学
郑洁文6 小时前
基于SpringBoot的商品仓库管理系统的设计与实现
java·spring boot·后端·仓库管理系统·商品仓库管理系统
该用户已不存在6 小时前
这9款开发工具夯爆了,用了都说好
后端·程序员·全栈
KeepPush6 小时前
Python迭代器与生成器:从原理到实战的深度解析
后端
CTA终结者6 小时前
期货开仓前保证金够吗:get_account 可用与占用字段对照
python·区块链