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(繼承/自訂類別)。

那麼該選哪一種?
大多數「視圖級別速率限制」 → 方式 B(ScopedRateThrottle)
- 代碼最少。
- 所有策略可在設定檔集中管理。
- 視圖只需寫
throttle_scope。 - 未設定範圍的視圖不受限。
若符合以下任一條件 → 方式 A(繼承/自訂類別)
- 想在同一視圖上同時套用「突發 + 持續」等多個限制。
- 需要「使用者/IP」以外的自訂基準(如 username+IP、tenant、API key)。
- 不想改動全域設定,只想在特定視圖上強制套用。
- 想透過類別名稱即時了解策略意圖。
相關文章:
目前沒有評論。