限制接口訪問頻率

限流,就是限制對(duì) API 的調(diào)用頻率。每一次 API 調(diào)用,都要花費(fèi)服務(wù)器的資源,因此很多 API 不會(huì)對(duì)用戶無(wú)限次地開放,請(qǐng)求達(dá)到某個(gè)次數(shù)后就不再允許訪問了,或者一段時(shí)間內(nèi),最多只允許訪問 API 指定次數(shù)。

django-rest-framework 為我們提供了 2 個(gè)常用的限流功能輔助類,分別是 AnonRateThrottle 和 - UserRateThrottle。

1 - AnonRateThrottle

AnonRateThrottle 用于限制未認(rèn)證用戶的訪問頻率,限制依據(jù)是用戶的 ip。

2 - UserRateThrottle

UserRateThrottle 用于限定認(rèn)證用戶,即網(wǎng)站的注冊(cè)用戶(目前我們博客不支持用戶登錄注冊(cè),所以這個(gè)類沒什么用)。兩個(gè)類可以用于同一 API,以便對(duì)不同類型的用戶實(shí)施不同的限流政策。

AnonRateThrottle 和 UserRateThrottle 這兩個(gè)輔助類限制頻率的指定格式為 "最大訪問次數(shù)/時(shí)間間隔",例如設(shè)置為 10/min,則只允許一分鐘內(nèi)最多調(diào)用接口 10 次。
超過限定次數(shù)的調(diào)用將拋出 exceptions.Throttled 異常,客戶端收到 429 狀態(tài)碼(too many requests)的響應(yīng)。

3 - 根據(jù)已有 API 列表和緩存情況來(lái)分析一下我們的限流政策:
接口名         URL                     限流
文章列表    /api/posts/               10/min
文章詳情    /api/posts/:id/           10/min
分類列表    /categories/              10/min
標(biāo)簽列表    /tags/                    10/min
歸檔日期列表  /posts/archive/dates/    10/min
評(píng)論列表    /api/posts/:id/comments/  10/min
文章搜索結(jié)果  /api/search/             5/min
  • (1) 首頁(yè)文章列表 API:有緩存,正常用戶不會(huì)訪問太頻繁,限定 10/min
  • (2) 文章詳情 API:有緩存,正常用戶不會(huì)訪問太頻繁,限定 10/min
  • (3) 分類、標(biāo)簽、歸檔日期列表,有緩存,正常用戶不會(huì)訪問太頻繁,限定 10/min
  • (4) 評(píng)論列表,有緩存,正常用戶不會(huì)訪問太頻繁,限定 10/min
  • (5) 搜索接口,正常用戶不會(huì)訪問太頻繁,限定 5/min
4 - 啟用限流有 2 種方式:一是全局設(shè)置,二是單個(gè)視圖設(shè)置;

單個(gè)視圖的設(shè)置會(huì)覆蓋全局設(shè)置。因?yàn)閹缀跛薪涌诙际菍?duì)匿名用戶限流,因此先來(lái)進(jìn)行全局設(shè)置。在項(xiàng)目配置文件 settings.py 中找到 REST_FRAMEWORK 配置項(xiàng),加入如下配置:

REST_FRAMEWORK = {
   'DEFAULT_THROTTLE_CLASSES': [
       'rest_framework.throttling.AnonRateThrottle',
   ],
   'DEFAULT_THROTTLE_RATES': {
       'anon': '10/min',
   }
}

這樣,所有接口訪問頻率均被設(shè)置為 10/min。
對(duì)于搜索接口,我們制定的限流規(guī)則是 5/min,因此我們對(duì)這個(gè)視圖集的限流類進(jìn)行單獨(dú)設(shè)置。

因?yàn)槿峙渲弥校J(rèn)設(shè)置的限流頻率為 10/min,為了將限流類的默認(rèn)頻率設(shè)置為 5/min,我們需要繼承原限流類覆蓋它的 THROTTLE_RATES 屬性,代碼非常簡(jiǎn)單:

# 在views.py視圖函數(shù)里添加
from rest_framework.throttling import AnonRateThrottle

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

接著在搜索接口的視圖集中通過 throttle_classes 指定這個(gè)限流類:

class PostSearchView(HaystackViewSet):
    index_models = [Post]
    serializer_class = PostHaystackSerializer
    throttle_classes = [PostSearchAnonRateThrottle]
5 - 現(xiàn)在來(lái)測(cè)試 10/min 訪問限制的接口,以文章列表接口 api/v1/posts/ 為例,在連續(xù)訪問 10 次后,接口返回了如下結(jié)果:
HTTP 429 Too Many Requests
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Retry-After: 52
Vary: Accept

{
"detail": "請(qǐng)求超過了限速。 Expected available in 52 seconds."
}
  • 一分鐘后重新訪問又恢復(fù)了正常。
6 - 再來(lái)測(cè)試一下搜索接口,訪問 /api/v1/search/?text=markdown,在連續(xù)刷新 5 次后,接口返回如下結(jié)果:
HTTP 429 Too Many Requests
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Retry-After: 26
Vary: Accept

{
"detail": "請(qǐng)求超過了限速。 Expected available in 26 seconds."
}
  • 一分鐘后重新訪問又恢復(fù)了正常。

?? 注意

如果搜索功能依賴 Elasticsearch 服務(wù),因此測(cè)試接口時(shí)需要運(yùn)行 Docker 容器,可參考 基于 drf-haystack 實(shí)現(xiàn)文章搜索接口。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容