接口限流:限制接口的訪問頻率


限流,顧名思義,就是限制對 API 的調用頻率。每一次 API 調用,都要花費服務器的資源,因此很多 API 不會對用戶無限次地開放,請求達到某個次數后就不再允許訪問了,或者一段時間內,最多只允許訪問 API 指定次數。

目前,我們的接口是沒有任何限流措施的,只要用戶調用接口,服務器就會處理並返回數據。為了防止接口被惡意用戶刷爆,我們來給接口限流。

上一篇中我們已經整理了接口並加入了緩存,我們的限流政策可以根據緩存的設置情況來制定。對於緩存時間較長的接口,可以適當放寬限制,而對於可能需要訪問數據庫的接口,則進行嚴格的限制。

django-rest-framework 為我們提供了 2 個常用的限流功能輔助類,分別是 AnonRateThrottleUserRateThrottleAnonRateThrottle  用於限制未認證用戶的訪問頻率,限制依據是用戶的 ip。UserRateThrottle 用於限定認證用戶,即網站的注冊用戶(目前我們博客不支持用戶登錄注冊,所以這個類沒什么用)。兩個類可以用於同一 API,以便對不同類型的用戶實施不同的限流政策。

這兩個輔助類限制頻率的指定格式為 "最大訪問次數/時間間隔",例如設置為 10/min,則只允許一分鍾內最多調用接口 10 次。超過限定次數的調用將拋出 exceptions.Throttled 異常,客戶端收到 429 狀態碼(too many requests)的響應。

再次根據已有 API 列表和緩存情況來分析一下我們的限流政策:

接口名 URL 限流
文章列表 /api/posts/ 10/min
文章詳情 /api/posts/:id/ 10/min
分類列表 /categories/ 10/min
標簽列表 /tags/ 10/min
歸檔日期列表 /posts/archive/dates/ 10/min
評論列表 /api/posts/:id/comments/ 10/min
文章搜索結果 /api/search/ 5/min

補充說明:

  1. 首頁文章列表 API:有緩存,正常用戶不會訪問太頻繁,限定 10/min

  2. 文章詳情 API:有緩存,正常用戶不會訪問太頻繁,限定 10/min

  3. 分類、標簽、歸檔日期列表,有緩存,正常用戶不會訪問太頻繁,限定 10/min

  4. 評論列表,有緩存,正常用戶不會訪問太頻繁,限定 10/min

  5. 搜索接口,正常用戶不會訪問太頻繁,限定 5/min

接口限流規則制定好后,接下來就設置限流輔助類就可以了。

啟用限流有 2 種方式,一是全局設置,二是單個視圖設置,單個視圖的設置會覆蓋全局設置。因為幾乎所有接口都是對匿名用戶限流,因此先來進行全局設置。在項目配置文件 common.py 中找到 REST_FRAMEWORK 配置項,加入如下配置:

# filename="common.py"
REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': [
        'rest_framework.throttling.AnonRateThrottle',
    ],
    'DEFAULT_THROTTLE_RATES': {
        'anon': '10/min',
    }
}

這樣,所有接口訪問頻率均被設置為 10/min。

對於搜索接口,我們制定的限流規則是 5/min,因此我們對這個視圖集的限流類進行單獨設置。

因為全局配置中,默認設置的限流頻率為 10/min,為了將限流類的默認頻率設置為 5/min,我們需要繼承原限流類覆蓋它的 THROTTLE_RATES 屬性,代碼非常簡單:

# filename="blog/views.py"
from rest_framework.throttling import AnonRateThrottle

class PostSearchAnonRateThrottle(AnonRateThrottle):
    THROTTLE_RATES = {"anon": "5/min"}

接着在搜索接口的視圖集中通過 throttle_classes 指定這個限流類:

# filename="blog/views.py"
class PostSearchView(HaystackViewSet):
    index_models = [Post]
    serializer_class = PostHaystackSerializer
    throttle_classes = [PostSearchAnonRateThrottle]

我們來測試一下,限流是否真的起了作用。

首先來測試 10/min 訪問限制的接口,以文章列表接口 api/v1/posts/ 為例,在連續訪問 10 次后,接口返回了如下結果:

HTTP 429 Too Many Requests Allow: GET, HEAD, OPTIONS Content-Type: application/json Retry-After: 52 Vary: Accept

{ "detail": "請求超過了限速。Expected available in 52 seconds." }

一分鍾后重新訪問又恢復了正常。

再來測試一下搜索接口,訪問 /api/v1/search/?text=markdown,在連續刷新 5 次后,接口返回如下結果:

HTTP 429 Too Many Requests Allow: GET, HEAD, OPTIONS Content-Type: application/json Retry-After: 26 Vary: Accept

{ "detail": "請求超過了限速。Expected available in 26 seconds." }

一分鍾后重新訪問又恢復了正常。


!!! note "注意"

因為搜索功能依賴 Elasticsearch 服務,因此測試接口時需要運行 Docker 容器,可參考《基於 drf-haystack 實現文章搜索接口》這篇文章。

https://www.zmrenwu.com/courses/django-rest-framework-tutorial/materials/101/

參考資料

[1]

HelloGitHub-追夢人物: https://www.zmrenwu.com




點個“在看”支持一下????


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM