# DRF 範圍限制的兩種寫法:ScopedRateThrottle 與 UserRateThrottle 繼承比較 在 DRF 中實作基於範圍的速率限制時,常見的兩種模式如下。 * **方式 A**:繼承 `UserRateThrottle`(或 `SimpleRateThrottle`)並在自訂類別中設定 `scope`,再將此類別直接加入 `throttle_classes`。 * **方式 B**:在 `DEFAULT_THROTTLE_CLASSES` 設定中加入 `ScopedRateThrottle`,視圖只需設定 `throttle_scope = "login"`。 先回答「究竟效果相同嗎?」: > **若只想以「使用者 ID(或未登入 IP)+ 範圍」為單一限制條件,兩者結果幾乎相同。** > 但在實作方式(避免錯誤、擴充性、程式碼結構)上會有差異,進而決定選擇。 --- ## 共通點:兩者皆以「範圍 + (使用者 ID 或 IP)」作為鍵 {#sec-431a00e0f2d6} * `ScopedRateThrottle` 會在視圖中若有 `throttle_scope`,以「範圍 + 使用者 ID / IP」組成鍵,並從 `DEFAULT_THROTTLE_RATES` 取得對應速率。 * `UserRateThrottle` 亦預設以「使用者 ID」或「IP」為限制基礎,若需多個限制,官方範例會透過繼承並改變 `scope`。 --- ## 差異 1) 「在哪裡寫範圍」:視圖屬性 vs 類別屬性 {#sec-d624b1b24a23} ### 方式 A:在類別中固定範圍(明確) {#sec-8806ad9d3f5f} ```python 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 解析(設定為主) {#sec-21174dce63ed} ```python 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 視圖裝配 {#sec-693e9b27f525} ### 方式 B 的重點(常被誤解) {#sec-579edda7168e} 即使在 `DEFAULT_THROTTLE_CLASSES` 加入 `ScopedRateThrottle`,**若視圖未設定 `throttle_scope`,也不會套用**。 因此「全域設定會阻塞所有 API」的擔憂通常不必要。 ### 方式 A 的優勢 {#sec-1d7d8c13bc83} 不必改動全域設定,即可在「特定視圖」上安裝所需的 throttle。 在團隊或服務結構不易改動設定,或只想強制某些端點時特別方便。 --- ## 差異 3) 擴充性:當「單一限制」之外的需求出現時,方式 A 更具優勢 {#sec-76818ce0201b} 兩者在「單一視圖、單一範圍、單一速率」時相似,差異在於更複雜的情境。 ### 1) 想在同一視圖上同時套用「突發 + 持續」等多個 throttle {#sec-c0ea02305999} DRF 文件亦示範多個 `UserRateThrottle` 同時使用。 ```python class Burst(UserRateThrottle): scope = "burst" class Sustained(UserRateThrottle): scope = "sustained" class SearchView(APIView): throttle_classes = [Burst, Sustained] ``` 僅靠 `ScopedRateThrottle` 難以自然表達「同一視圖有兩個範圍」;必須使用類別或自訂實作。 ### 2) 「限制基準」改變的瞬間 {#sec-39de8e67072d} `ScopedRateThrottle` 預設以「使用者 ID / IP」為基礎。實務上常見需求: * 登入:以 **IP + 使用者名稱** 組合限制(防止帳號針對攻擊)。 * 組織/租戶:以 **tenant_id** 為單位限制。 * API Key:以 **金鑰** 為單位限制。 這些都需要覆寫 `get_cache_key()` 等邏輯,最自然的做法是使用方式 A(繼承/自訂類別)。 --- ![API連接的兩把鑰匙](/media/editor_temp/6/e98f026a-a38e-43ca-8c86-fa7966dd3cdf.png) ## 那麼該選哪一種? {#sec-1cf080d47909} ### 大多數「視圖級別速率限制」 → 方式 B(ScopedRateThrottle) * 代碼最少。 * 所有策略可在設定檔集中管理。 * 視圖只需寫 `throttle_scope`。 * 未設定範圍的視圖不受限。 ### 若符合以下任一條件 → 方式 A(繼承/自訂類別) * 想在同一視圖上同時套用「突發 + 持續」等多個限制。 * 需要「使用者/IP」以外的自訂基準(如 username+IP、tenant、API key)。 * 不想改動全域設定,只想在特定視圖上強制套用。 * 想透過類別名稱即時了解策略意圖。 **相關文章:** - [DRF Throttling 完全攻略:設定、應用、客製化指引](/ko/whitedec/2026/1/26/drf-throttling-complete-guide/)