优先选AnonRateThrottle(仅限匿名用户),因其是SimpleRateThrottle的预置子类、开箱即用;需按用户角色、路径或租户等自定义限流时,必须继承SimpleRateThrottle并重写get_cache_key()。

限流类怎么选:SimpleRateThrottle 还是 AnonRateThrottle?
Django REST framework(DRF)内置的限流机制依赖于继承 BaseThrottle 的类,最常用的是 SimpleRateThrottle。它支持自定义限流逻辑,比如按用户 ID、IP 或请求路径区分;而 AnonRateThrottle 和 UserRateThrottle 只是它的子类,分别针对未认证和已认证用户做了默认实现。
- 如果你只需要对匿名用户限流,直接用
AnonRateThrottle最省事 - 如果要按用户角色、租户 ID 或 API 路径做差异化限流,必须继承
SimpleRateThrottle并重写get_cache_key() - 不要用
UserRateThrottle处理匿名请求——它对request.user.is_authenticated == False返回None,导致该请求完全绕过限流
注意:所有限流类都依赖 DRF 的缓存后端(如 Redis 或 LocMemCache),如果没配缓存,SimpleRateThrottle 会退化为每请求都查数据库(极慢),甚至抛出 RuntimeError: No cache backend configured。
如何配置 rate 字符串:"100/day" 的语法细节
DRF 限流的速率由字符串控制,格式为 "<number>/<period>"</period></number>,其中 period 必须是 second、minute、hour 或 day(不支持复数或缩写,"100/min" 会报错)。
-
"5/minute"表示每分钟最多 5 次请求(从第一次触发开始计时,不是自然分钟) -
"100/hour"实际对应一个滑动窗口:DRF 内部用时间戳 + 计数器实现,不是固定整点重置 - 多个限流规则可叠加,比如同时声明
AnonRateThrottle和UserRateThrottle,任一触发即拒绝请求 - 若想对某个视图单独设限,不要改全局
DEFAULT_THROTTLE_CLASSES,而是直接在视图类里写:throttle_classes = [MyCustomThrottle]
常见错误:把 rate = "100/day" 写成 rate = "100 per day" ——中间空格或多余字符会导致解析失败,静默失效(请求永远不被限)。
立即学习“Python免费学习笔记(深入)”;
创建 Flask + Vue.js 全栈项目,采用单端口架构、uv 依赖管理、结构化日志和生产级前端设计。当用户要求以下操作时触发:创建新的 Flask+Vue 项目、搭建 Web 应用、构建全栈 Python+Vue 应用、初始化 Flask Web 项目、设置单端口 Flask 前后端项目。触发词:新建项目、创建项目、搭建项目、Flask项目、Vue项目。
自定义限流:按 request.path 或 tenant_id 区分流量
当需要“每个租户每天最多调用 /api/v1/orders/ 接口 1000 次”,就得自己写限流类:
class TenantPathThrottle(SimpleRateThrottle):
scope = 'tenant_path'
<pre class='brush:python;toolbar:false;'>def get_cache_key(self, request, view):
if not request.user.is_authenticated:
return None
# 组合租户ID + 请求路径作为唯一key
tenant_id = getattr(request.user, 'tenant_id', 'unknown')
path = request.path
return f'throttle_{tenant_id}_{path}'-
scope是缓存 key 前缀,必须和settings.py中的THROTTLE_RATES键名一致 -
get_cache_key()返回None表示跳过限流(比如对登录接口放行) - 切勿在
get_cache_key()里做数据库查询——它在每次请求前调用,会成为性能瓶颈 - 如果用 Redis 缓存,key 实际存储为
throttle_<tenant_id><em>/api/v1/orders/</em></tenant_id>,可用redis-cli keys "throttle*"检查
容易忽略的一点:DRF 默认用 cache.set(key, value, timeout) 存储计数,但 timeout 是硬编码的(如 minute 对应 60 秒)。如果你改了系统时间或用了时钟漂移大的容器,可能导致限流窗口错乱。
调试限流失败:为什么 X-RateLimit-Remaining 总是 -1?
DRF 会在响应头中添加 X-RateLimit-Limit、X-RateLimit-Remaining 和 X-RateLimit-Reset,但这些字段只在启用限流且缓存正常时才出现。
- 如果响应头里没有这些字段,先确认视图是否真的应用了限流类(
print(view.throttle_classes)) -
X-RateLimit-Remaining: -1表示当前请求已被拒绝(HTTP 429),但 DRF 仍会写入响应头 - 本地开发用
LocMemCache时,不同进程间缓存不共享,多开几个终端测试会误判为“没生效” - 真实环境务必用 Redis,并确保
CACHES配置中的KEY_PREFIX不为空(否则多个服务实例可能 key 冲突)
最隐蔽的问题:限流类的 allow_request() 方法抛异常(比如访问了不存在的 request.auth 属性)会导致整个请求 500,而不是 429——这种错误不会打日志,只能靠单元测试覆盖。

















