限流(Throttling)
限流與許可權類似,因為它確定是否應該授權請求。 限流閥指示臨時狀態,並用於控制客戶端可以對API進行的請求速率。
與許可權一樣,可能會使用多種限流方式。你的 API 可能對未經身份驗證的請求進行限流,對經過身份驗證的請求限流較少。
如果你需要對 API 的不同部分使用不同的限流策略,由於某些服務特別佔用資源,你可能想要使用同時有多種限流策略的另一種方案。
如果你想要同時實現爆發限流率和持續限流率,也可以使用多個限流閥。例如,你可能希望將使用者限制為每分鐘最多 60 個請求,並且每天最多 1000 個請求。
限流閥不一定只限制請求頻率。例如,儲存服務可能還需要對頻寬進行限制,而付費資料服務可能希望對正在訪問的某些記錄進行限制。
如何確定限流
與許可權和身份驗證一樣,REST framework 中的限流始終定義為類的列表。
在執行檢視的主體之前,會檢查列表中的每個限流閥。如果任何限流檢查失敗,將引發一個 exceptions.Throttled
異常,並且該檢視的主體將不會再執行。
設定限流策略
可以使用 DEFAULT_THROTTLE_CLASSES
和 DEFAULT_THROTTLE_RATES
setting 全域性設定預設限流策略。例如:
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': (
'rest_framework.throttling.AnonRateThrottle',
'rest_framework.throttling.UserRateThrottle'
),
'DEFAULT_THROTTLE_RATES': {
'anon': '100/day',
'user': '1000/day'
}
}
複製程式碼
DEFAULT_THROTTLE_RATES
中使用的頻率描述可能包括 second
,minute
,hour
或 day
作為限流期。
你還可以使用基於 APIView
類的檢視,在每個檢視或每個檢視集的基礎上設定限流策略。
from rest_framework.response import Response
from rest_framework.throttling import UserRateThrottle
from rest_framework.views import APIView
class ExampleView(APIView):
throttle_classes = (UserRateThrottle,)
def get(self, request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
複製程式碼
或者在基於 @api_view
裝飾器的函式檢視上設定。
@api_view(['GET'])
@throttle_classes([UserRateThrottle])
def example_view(request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
複製程式碼
如何識別客戶端
X-Forwarded-For
HTTP header 和 REMOTE_ADDR
WSGI 變數用於唯一標識用於限流的客戶端 IP 地址。如果存在 X-Forwarded-For
header ,則會使用它,否則將使用 WSGI 環境中的 REMOTE_ADDR
變數的值。
如果你需要嚴格標識唯一的客戶端 IP 地址,則需要先通過設定 NUM_PROXIES
setting 來配置 API 執行的應用代理的數量。該設定應該是一個零或更大的整數。如果設定為非零,則一旦任何應用程式代理 IP 地址首先被排除,客戶端 IP 將被標識為 X-Forwarded-For
header 中的最後一個 IP 地址。如果設定為零,則 REMOTE_ADDR
值將始終用作識別 IP 地址。
重要的是要理解,如果你配置了 num_proxy
設定,那麼在一個唯一的 NAT 的閘道器後面的所有客戶端將被當作一個單獨的客戶機來對待。
關於 X-Forwarded-For
header 如何工作以及識別遠端客戶端 IP 的更多內容可以在這裡找到。
設定快取
REST framework 提供的限流類使用 Django 的快取後端。你應該確保你已經設定了適當的快取 setting 。對於簡單的設定,LocMemCache
後端的預設值應該沒問題。有關更多詳細資訊,請參閱 Django 的快取文件。
如果你需要使用 'default'
以外的快取,則可以通過建立自定義限流類並設定 cache
屬性來實現。例如:
class CustomAnonRateThrottle(AnonRateThrottle):
cache = get_cache('alternate')
複製程式碼
您需要記住還要在 'DEFAULT_THROTTLE_CLASSES'
settings key 中設定自定義的限流類,或者使用 throttle_classes
檢視屬性。
API 參考
AnonRateThrottle
AnonRateThrottle
將永遠限制未認證的使用者。通過傳入請求的 IP 地址生成一個唯一的金鑰來進行限制。
允許的請求頻率由以下之一決定(按優先順序)。
- 類的
rate
屬性,可以通過繼承AnonRateThrottle
並設定屬性來提供。 DEFAULT_THROTTLE_RATES['anon']
設定.
如果你想限制未知來源的請求頻率,AnonRateThrottle
是合適的。
UserRateThrottle
UserRateThrottle
通過 API 將使用者請求限制為給定的請求頻率。使用者標識用於生成一個唯一的金鑰來加以限制。未經身份驗證的請求將回退到使用傳入請求的 IP 地址生成一個唯一的金鑰來進行限制。
允許的請求頻率由以下之一決定(按優先順序)。
- 類的
rate
屬性,可以通過繼承UserRateThrottle
並設定屬性來提供。 DEFAULT_THROTTLE_RATES['user']
設定.
一個 API 可能同時具有多個 UserRateThrottles
。為此,請繼承 UserRateThrottle
併為每個類設定一個唯一的“範圍”。
例如,多個使用者限流率可以通過使用以下類來實現......
class BurstRateThrottle(UserRateThrottle):
scope = 'burst'
class SustainedRateThrottle(UserRateThrottle):
scope = 'sustained'
複製程式碼
...和以下設定。
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': (
'example.throttles.BurstRateThrottle',
'example.throttles.SustainedRateThrottle'
),
'DEFAULT_THROTTLE_RATES': {
'burst': '60/min',
'sustained': '1000/day'
}
}
複製程式碼
如果希望對每個使用者進行簡單的全域性速率限制,那麼 UserRateThrottle
是合適的。
ScopedRateThrottle
ScopedRateThrottle
類可用於限制對 API 特定部分的訪問。只有當正在訪問的檢視包含 .throttle_scope
屬性時才會應用此限制。然後通過將請求的 “範圍” 與唯一的使用者標識或 IP 地址連線起來形成唯一的限流金鑰。
允許的請求頻率由 DEFAULT_THROTTLE_RATES
setting 使用請求 “範圍” 中的一個鍵確定。
例如,給出以下檢視...
class ContactListView(APIView):
throttle_scope = 'contacts'
...
class ContactDetailView(APIView):
throttle_scope = 'contacts'
...
class UploadView(APIView):
throttle_scope = 'uploads'
...
複製程式碼
...和以下設定。
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': (
'rest_framework.throttling.ScopedRateThrottle',
),
'DEFAULT_THROTTLE_RATES': {
'contacts': '1000/day',
'uploads': '20/day'
}
}
複製程式碼
使用者對 ContactListView
或 ContactDetailView
的請求將被限制為每天 1000 次。使用者對 UploadView
的請求將被限制為每天 20 次。
自定義限流
要自定義限流,請繼承 BaseThrottle
類並實現 .allow_request(self, request, view)
方法。如果請求被允許,該方法應該返回 True
,否則返回 False
。
或者,你也可以重寫 .wait()
方法。如果實現,.wait()
應該返回建議的秒數,在嘗試下一次請求之前等待,或者返回 None
。如果 .allow_request()
先前已經返回 False
,則只會呼叫 .wait()
方法。
如果 .wait()
方法被實現並且請求受到限制,那麼 Retry-After
header 將包含在響應中。
舉個例子
以下是限流的一個示例,隨機地控制每 10 次請求中的 1 次。
import random
class RandomRateThrottle(throttling.BaseThrottle):
def allow_request(self, request, view):
return random.randint(1, 10) != 1
複製程式碼