FastAPI精确限流:API级防刷实战

在 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 + 自定义限流键

如果你需要按 用户 IDAPI 路径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 ClusterRedis Sentinel 保证高可用。
  • 开启 Redis 持久化(RDB/AOF)防止限流数据丢失。
  • 在 Nginx 层也加一层限流(防 DDoS 入口)。
  • 监控限流命中情况(如 Prometheus + Grafana)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值