DRF Throttling 中使用 scope 的两种方式比较:ScopedRateThrottle 与 UserRateThrottle 继承
在 DRF 中实现基于 scope 的限流时,常见的两种模式如下。
- 方式 A:继承
UserRateThrottle(或SimpleRateThrottle),创建一个带有固定 scope 的自定义类,并直接在视图中通过throttle_classes指定。 - 方式 B:在
DEFAULT_THROTTLE_CLASSES中注册ScopedRateThrottle,然后在视图中仅设置throttle_scope = "login"。
先回答“最终效果是否相同?”的问题:
当你只想按“用户 ID(或未登录 IP)+ scope”来限制速率时,两种方式的结果几乎相同。区别主要体现在: - 实现方式(防止错误) - 可扩展性(多策略/自定义基准) - 代码结构(设置中心 vs 代码中心)
共同点:两者都使用 “scope + (user id 或 IP)” 生成键
ScopedRateThrottle在视图中存在throttle_scope时,会以 scope + 用户 ID / IP 组合生成键,并在DEFAULT_THROTTLE_RATES中查找对应的速率。UserRateThrottle默认按 已认证用户的 user id 或 未认证用户的 IP 限制;若需要多种策略,官方示例建议通过继承并为每个类设置不同的 scope。
差异 1:scope 的位置——视图属性 vs 类属性
方式 A:在类中固定 scope(显式)
from rest_framework.throttling import UserRateThrottle
from rest_framework.views import APIView
class CustomDomainSaveThrottle(UserRateThrottle):
scope = "custom_domain_save"
class SaveCustomDomainView(APIView):
throttle_classes = [CustomDomainSaveThrottle]
- scope 固定在类中。
- 视图只需声明使用该类即可。
- 减少了在每个视图中手动输入 scope 字符串时的拼写错误。
方式 B:在视图中仅设置 scope,使用共享 throttle(设置中心)
REST_FRAMEWORK = {
"DEFAULT_THROTTLE_CLASSES": [
"rest_framework.throttling.ScopedRateThrottle",
],
"DEFAULT_THROTTLE_RATES": {
"login": "5/min",
}
}
from rest_framework.views import APIView
class LoginView(APIView):
throttle_scope = "login"
- scope 直接写在视图属性中。
- 共享的
ScopedRateThrottle会根据视图的throttle_scope在设置中查找速率。 - 代码更简洁,所有策略集中在 settings 中管理。
差异 2:谁来保证应用——全局注册 vs 视图挂载
方式 B 的关键点(常被误解)
即使在 DEFAULT_THROTTLE_CLASSES 中加入 ScopedRateThrottle,没有 throttle_scope 的视图也不会被限流。因此,担心全局注册会导致所有 API 都被限制的情况通常不必担心。
方式 A 的优势
不需要改动全局设置即可仅在特定视图上挂载所需的限流策略。适用于团队或服务结构中无法频繁修改 settings,或只想对某些端点强制限流的场景。
差异 3:可扩展性——单一限制之外的场景更适合方式 A
两种方式在“单一视图、单一 scope、单一速率”时表现相似。随后差异显现。
1) 在同一视图上使用多种限流(如 burst + sustained)
DRF 文档示例展示了同时使用多个 UserRateThrottle 的模式:
class Burst(UserRateThrottle):
scope = "burst"
class Sustained(UserRateThrottle):
scope = "sustained"
class SearchView(APIView):
throttle_classes = [Burst, Sustained]
仅靠 ScopedRateThrottle 难以自然表达“同一视图拥有两个 scope”,因此需要自定义类或实现。
2) 限制基准从 user/IP 变更
ScopedRateThrottle 默认按 user id / IP 计算键。实际业务中常见需求:
- 登录:按 IP + username 组合 限制(防止账号定向攻击)
- 组织/租户:按 tenant_id 限制
- API Key:按 key 限制
这些情况需要自定义 get_cache_key() 等逻辑,天然倾向于方式 A(继承/自定义类)。

那么应该选哪种?
大多数“按视图限流”场景 → 方式 B(ScopedRateThrottle)
- 代码最小化
- 在 settings 中统一管理策略
- 视图仅需声明
throttle_scope - 没有
throttle_scope的视图不受限流
以下任一情况 → 方式 A(继承/自定义类)
- 同一视图需要 多重限流(burst + sustained 等)
- 限制基准不是 user/IP(如 username+IP、tenant、API key 等)
- 需要避免全局设置变更,只在特定视图强制限流
- 想通过类名将策略“文档化”,让阅读者一眼看出意图
相关文章: