Django REST framework API 指南(15):限流

官方原文連接
本系列文章 github 地址
轉載請註明出處php

限流(Throttling)

限流與權限相似,由於它肯定是否應該受權請求。 限流閥指示臨時狀態,並用於控制客戶端能夠對API進行的請求速率。python

與權限同樣,可能會使用多種限流方式。你的 API 可能對未經身份驗證的請求進行限流,對通過身份驗證的請求限流較少。git

若是你須要對 API 的不一樣部分使用不一樣的限流策略,因爲某些服務特別佔用資源,你可能想要使用同時有多種限流策略的另外一種方案。github

若是你想要同時實現爆發限流率和持續限流率,也能夠使用多個限流閥。例如,你可能但願將用戶限制爲每分鐘最多 60 個請求,而且天天最多 1000 個請求。django

限流閥不必定只限制請求頻率。例如,存儲服務可能還須要對帶寬進行限制,而付費數據服務可能但願對正在訪問的某些記錄進行限制。後端

如何肯定限流

與權限和身份驗證同樣,REST framework 中的限流始終定義爲類的列表。api

在運行視圖的主體以前,會檢查列表中的每一個限流閥。若是任何限流檢查失敗,將引起一個 exceptions.Throttled 異常,而且該視圖的主體將不會再執行。緩存

設置限流策略

能夠使用 DEFAULT_THROTTLE_CLASSESDEFAULT_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 中使用的頻率描述可能包括 secondminutehourday 做爲限流期。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 視圖屬性。


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'
    }
}
複製代碼

用戶對 ContactListViewContactDetailView 的請求將被限制爲天天 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
複製代碼
相關文章
相關標籤/搜索