限流與權限相似,由於它肯定是否應該受權請求。 限流閥指示臨時狀態,並用於控制客戶端能夠對API進行的請求速率。python
與權限同樣,可能會使用多種限流方式。你的 API 可能對未經身份驗證的請求進行限流,對通過身份驗證的請求限流較少。git
若是你須要對 API 的不一樣部分使用不一樣的限流策略,因爲某些服務特別佔用資源,你可能想要使用同時有多種限流策略的另外一種方案。github
若是你想要同時實現爆發限流率和持續限流率,也能夠使用多個限流閥。例如,你可能但願將用戶限制爲每分鐘最多 60 個請求,而且天天最多 1000 個請求。django
限流閥不必定只限制請求頻率。例如,存儲服務可能還須要對帶寬進行限制,而付費數據服務可能但願對正在訪問的某些記錄進行限制。後端
與權限和身份驗證同樣,REST framework 中的限流始終定義爲類的列表。api
在運行視圖的主體以前,會檢查列表中的每一個限流閥。若是任何限流檢查失敗,將引起一個 exceptions.Throttled
異常,而且該視圖的主體將不會再執行。緩存
能夠使用 DEFAULT_THROTTLE_CLASSES
和 DEFAULT_THROTTLE_RATES
setting 全局設置默認限流策略。例如:dom
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
做爲限流期。ide
你還能夠使用基於 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
視圖屬性。
AnonRateThrottle
將永遠限制未認證的用戶。經過傳入請求的 IP 地址生成一個惟一的密鑰來進行限制。
容許的請求頻率由如下之一決定(按優先順序)。
rate
屬性,能夠經過繼承 AnonRateThrottle
並設置屬性來提供。DEFAULT_THROTTLE_RATES['anon']
設置.若是你想限制未知來源的請求頻率,AnonRateThrottle
是合適的。
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
類可用於限制對 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
複製代碼