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(继承/自定义类)。


API 连接的两把钥匙

那么应该选哪种?

大多数“按视图限流”场景 → 方式 B(ScopedRateThrottle)

  • 代码最小化
  • 在 settings 中统一管理策略
  • 视图仅需声明 throttle_scope
  • 没有 throttle_scope 的视图不受限流

以下任一情况 → 方式 A(继承/自定义类)

  • 同一视图需要 多重限流(burst + sustained 等)
  • 限制基准不是 user/IP(如 username+IP、tenant、API key 等)
  • 需要避免全局设置变更,只在特定视图强制限流
  • 想通过类名将策略“文档化”,让阅读者一眼看出意图

相关文章