DRF 範圍限制的兩種寫法:ScopedRateThrottle 與 UserRateThrottle 繼承比較

在 DRF 中實作基於範圍的速率限制時,常見的兩種模式如下。

  • 方式 A:繼承 UserRateThrottle(或 SimpleRateThrottle)並在自訂類別中設定 scope,再將此類別直接加入 throttle_classes
  • 方式 B:在 DEFAULT_THROTTLE_CLASSES 設定中加入 ScopedRateThrottle,視圖只需設定 throttle_scope = "login"

先回答「究竟效果相同嗎?」:

若只想以「使用者 ID(或未登入 IP)+ 範圍」為單一限制條件,兩者結果幾乎相同。 但在實作方式(避免錯誤、擴充性、程式碼結構)上會有差異,進而決定選擇。


共通點:兩者皆以「範圍 + (使用者 ID 或 IP)」作為鍵

  • ScopedRateThrottle 會在視圖中若有 throttle_scope,以「範圍 + 使用者 ID / IP」組成鍵,並從 DEFAULT_THROTTLE_RATES 取得對應速率。
  • UserRateThrottle 亦預設以「使用者 ID」或「IP」為限制基礎,若需多個限制,官方範例會透過繼承並改變 scope

差異 1) 「在哪裡寫範圍」:視圖屬性 vs 類別屬性

方式 A:在類別中固定範圍(明確)

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]
  • 範圍被 硬編碼於類別
  • 視圖只需宣告使用此類別即可。
  • 減少因在視圖中輸入範圍字串時的錯別字風險(類別名稱即為文件)。

方式 B:在視圖中寫範圍,通用 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"
  • 範圍直接寫在視圖中。
  • 通用 throttle (ScopedRateThrottle) 會判斷「這個視圖是 login 範圍」並從設定中取速率。
  • 程式碼簡潔,所有策略可在設定檔統一管理。

差異 2) 「誰保證套用」:全域註冊 vs 視圖裝配

方式 B 的重點(常被誤解)

即使在 DEFAULT_THROTTLE_CLASSES 加入 ScopedRateThrottle若視圖未設定 throttle_scope,也不會套用。 因此「全域設定會阻塞所有 API」的擔憂通常不必要。

方式 A 的優勢

不必改動全域設定,即可在「特定視圖」上安裝所需的 throttle。 在團隊或服務結構不易改動設定,或只想強制某些端點時特別方便。


差異 3) 擴充性:當「單一限制」之外的需求出現時,方式 A 更具優勢

兩者在「單一視圖、單一範圍、單一速率」時相似,差異在於更複雜的情境。

1) 想在同一視圖上同時套用「突發 + 持續」等多個 throttle

DRF 文件亦示範多個 UserRateThrottle 同時使用。

class Burst(UserRateThrottle):
    scope = "burst"

class Sustained(UserRateThrottle):
    scope = "sustained"

class SearchView(APIView):
    throttle_classes = [Burst, Sustained]

僅靠 ScopedRateThrottle 難以自然表達「同一視圖有兩個範圍」;必須使用類別或自訂實作。

2) 「限制基準」改變的瞬間

ScopedRateThrottle 預設以「使用者 ID / IP」為基礎。實務上常見需求:

  • 登入:以 IP + 使用者名稱 組合限制(防止帳號針對攻擊)。
  • 組織/租戶:以 tenant_id 為單位限制。
  • API Key:以 金鑰 為單位限制。

這些都需要覆寫 get_cache_key() 等邏輯,最自然的做法是使用方式 A(繼承/自訂類別)。


API連接的兩把鑰匙

那麼該選哪一種?

大多數「視圖級別速率限制」 → 方式 B(ScopedRateThrottle)

  • 代碼最少。
  • 所有策略可在設定檔集中管理。
  • 視圖只需寫 throttle_scope
  • 未設定範圍的視圖不受限。

若符合以下任一條件 → 方式 A(繼承/自訂類別)

  • 想在同一視圖上同時套用「突發 + 持續」等多個限制。
  • 需要「使用者/IP」以外的自訂基準(如 username+IP、tenant、API key)。
  • 不想改動全域設定,只想在特定視圖上強制套用。
  • 想透過類別名稱即時了解策略意圖。

相關文章: