在 FastAPI 中实现 精确到 API 接口层面的限流,构建一个高可用、防刷、防滥用系统。
✅ 目标:对每个 API 接口独立限流(如
/api/v1/users每秒最多 10 次请求),而不是全局统一限流。
✅ 推荐方案:使用 slowapi + redis 实现 API 级限流
这是目前 FastAPI 社区最成熟、最灵活 的方案。
📦 1. 安装依赖
pip install fastapi slowapi redis
slowapi是 FastAPI 的限流扩展,支持基于路径、用户、IP 等维度的限流。
🛠️ 2. 配置 Redis 作为限流存储
限流需要一个持久化存储(如 Redis)来记录请求频率。
# main.py
from fastapi import FastAPI
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded
import redis
# 初始化 Redis 客户端
redis_client = redis.from_url("redis://localhost:6379/0")
# 初始化限流器(基于 Redis)
limiter = Limiter(key_func=get_remote_address, storage_uri="redis://localhost:6379/0")
app = FastAPI()
# 注册限流异常处理
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
🔐 3. 对每个 API 接口精确限流
使用 @limiter.limit("10/minute") 装饰器,为每个路由单独配置限流策略。
from fastapi import Depends, Request
# 示例:用户接口限流
@app.get("/api/v1/users", dependencies=[Depends(limiter.limit("10/minute")))])
def get_users(request: Request):
return {"message": "获取用户列表", "rate_limit": "10/minute"}
# 示例:单个用户详情接口(更严格)
@app.get("/api/v1/users/{user_id}", dependencies=[Depends(limiter.limit("5/minute")))])
def get_user(user_id: int, request: Request):
return {"message": f"获取用户 {user_id} 信息", "rate_limit": "5/minute"}
# 示例:文件上传接口(限流更严)
@app.post("/api/v1/upload", dependencies=[Depends(limiter.limit("2/minute")))])
def upload_file(request: Request):
return {"message": "文件上传成功", "rate_limit": "2/minute"}
🎯 4. 限流策略说明("10/minute")
| 格式 | 含义 |
|---|---|
"10/minute" | 每分钟最多 10 次请求 |
"100/hour" | 每小时最多 100 次请求 |
"1/second" | 每秒最多 1 次请求 |
"1000/day" | 每天最多 1000 次请求 |
✅ 你可以为不同接口设置不同策略,实现精确到 API 层面的限流。
📊 5. 可选:使用 @limiter.limit + 自定义限流键
如果你需要按 用户 ID、API 路径、IP + 用户 ID 等维度限流,可以自定义 key_func。
from slowapi.util import get_remote_address
# 按用户 ID 限流(需从 token 解析用户)
def get_user_id(request: Request):
# 从 JWT token 中解析 user_id
token = request.headers.get("Authorization", "").replace("Bearer ", "")
# 假设你有一个解析函数
user_id = parse_jwt_token(token).get("user_id")
return f"user:{user_id}"
@app.get("/api/v1/profile", dependencies=[Depends(limiter.limit("5/minute", key_func=get_user_id)))])
def get_profile(request: Request):
return {"message": "获取用户资料"}
✅ 总结:FastAPI 精确到 API 层级限流的关键点
| 能力 | 实现方式 |
|---|---|
| ✅ 精确到每个 API 接口 | 使用 @limiter.limit("10/minute") 装饰每个路由 |
| ✅ 支持多种限流单位 | second, minute, hour, day |
| ✅ 支持按用户/IP/路径限流 | 自定义 key_func |
| ✅ 高性能、可扩展 | 使用 Redis 作为后端存储 |
| ✅ 异常友好 | 自动返回 429 Too Many Requests |
🚀 建议(生产环境)
- 使用 Redis Cluster 或 Redis Sentinel 保证高可用。
- 开启 Redis 持久化(RDB/AOF)防止限流数据丢失。
- 在 Nginx 层也加一层限流(防 DDoS 入口)。
- 监控限流命中情况(如 Prometheus + Grafana)。


1704

被折叠的 条评论
为什么被折叠?



