drf 訪問頻率限制
阿新 • • 發佈:2020-11-01
頻率限制
一個網站的訪問頻率限制是非常重要的,訪問頻率限制做的好可以預防爬蟲等惡意行為。
使用drf
的頻率限制對網站介面訪問做出限制十分的便捷好用,你只需要直接進行配置即可。
內建限制
區域性使用
首先我們在檢視中進行配置:
from rest_framework.throttling import UserRateThrottle # 已登入的 from rest_framework.throttling import AnonRateThrottle # 未登入的 from rest_framework.generics import GenericAPIView from rest_framework.response import Response from django.contrib import auth class ThrottleTestAPI(GenericAPIView): throttle_classes = [UserRateThrottle,AnonRateThrottle] def get(self,request): if request.user.is_authenticated: # 使用者一登陸 return Response(data="你的請求次數有十次每分鐘") return Response("你的請求次數只有三次每分鐘") def post(self,request): user_obj = auth.authenticate(username="admin",password="admin123") auth.login(request,user_obj) return Response("登入成功了")
其次,針對已登入的使用者和未登入的使用者,可以在settings
中進行配置限制次數:
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_RATES': { # 限制次數 , 未登入使用者一分鐘最多三次,登入使用者最多一分鐘十次
'anon': '3/m', # 會去配置的 UserRateThrottle 以及 AnonRateThrottle 中找到屬性 scope ,scope對應的就是生效的配置
'user': '10/m'
}
}
全域性使用
如果全域性使用,則可以進行如下配置:
REST_FRAMEWORK = { 'DEFAULT_THROTTLE_CLASSES': ( 'rest_framework.throttling.AnonRateThrottle', 'rest_framework.throttling.UserRateThrottle' ), 'DEFAULT_THROTTLE_RATES': { # 限制次數 , 未登入使用者一分鐘最多三次,登入使用者最多一分鐘十次 'anon': '3/m', # 會去配置的 UserRateThrottle 以及 AnonRateThrottle 中找到屬性 scope ,scope對應的就是生效的配置 'user': '10/m' } }
如果想針對某一個檢視取消全域性配置,則將throttle_classes
設定為空列表即可:
class ThrottleTestAPI(GenericAPIView): throttle_classes = [] def get(self,request): if request.user.is_authenticated: return Response(data="你的請求次數有十次每分鐘") return Response("你的請求次數只有三次每分鐘") def post(self,request): user_obj = auth.authenticate(username="admin",password="admin123") auth.login(request,user_obj) return Response("登入成功了")
自定製限制
頻率限制原理
drf
中的頻率控制基本原理是基於訪問次數和時間的,當然我們可以通過自己定義的方法來實現。當我們請求進來,走到我們頻率元件的時候,drf
內部會有一個字典來記錄訪問者的IP
以這個訪問者的IP
為key
,value
為一個列表,value
裡面存放訪問者每次訪問的時間,如下:
{ IP1: [第三次訪問時間,第二次訪問時間,第一次訪問時間],}
把每次訪問最新時間放入列表的最前面,記錄這樣一個數據結構後,通過什麼方式限流呢
如果我們設定的是10秒內只能訪問5次,
- 判斷訪問者的
IP
是否在這個請求IP
的字典裡
- 保證這個列表裡都是最近10秒內的訪問的時間。判斷當前請求時間和列表裡最早的(也就是最後的)請求時間的如果差大於10秒,說明請求以及不是最近10秒內的,刪除掉繼續判斷倒數第二個,直到差值小於10秒
- 判斷列表的長度(即訪問次數),是否大於我們設定的5次,如果大於就限流,否則放行,並把時間放入列表的最前面。
自定義限制
使用自定義限制時,需要建立一個類並且重寫allow_request()
以及wait()
方法。
allow_request()
有兩個額外的引數,分別是二次包裝後的request
物件,以及例項化過後的檢視類本身,當頻率限制通過後返回True
,否則返回False
。
wait()
方法是在return False
後觸發,必須返回一個int
型別的值來回複頻率限制還有多久取消。
class RequestLimit:
request_dict = {}
def __init__(self):
self.expiration = None
self.count = 3 # 設定最大訪問次數
self.seconds = 10 # 設定過期時間,秒為單位
def allow_request(self, request, view): # 自動呼叫該方法
# 拿出IP
ip = request.META.get("REMOTE_ADDR")
import time
current_time = time.time()
# 如果ip不在字典中,則新增即可,代表當前已訪問了一次
if not ip in self.request_dict:
self.request_dict[ip] = [current_time]
return True
# 如果在,判斷長度是否等於設定的最大訪問次數
if len(self.request_dict[ip]) == self.count:
# 如果等於最大訪問次數,則判斷最後一位的時間和當前時間相差是否大於指定的過期時間
if current_time - self.request_dict[ip][-1] > self.seconds:
# 如果大於,清空寫入
self.request_dict[ip].clear()
self.request_dict[ip].append(current_time)
return True
else:
# 如果不大於,說明時間還沒過,暫時不能訪問,設定多少秒後才能訪問
self.expiration = self.request_dict[ip][-1] + self.seconds
return False
# 如果在,長度不大於3,則追加當前時間
self.request_dict[ip].append(current_time)
return True
def wait(self):
import time
current_time = time.time()
result = self.expiration - current_time # 用過期的時間,減去當前的時間
return result
區域性使用
直接進行區域性使用即可,不要再到專案全域性資料夾下的settings.py
中做額外的配置了。
class ThrottleTestAPI(GenericAPIView):
throttle_classes = [app01.app01_throttle.RequestLimit] # 直接使用即可
def get(self,request):
return Response("get...")
f
全域性使用
全域性使用也不用再規定過期時間,直接在settings.py
中配置使用即可:
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES':['app01.app01_throttle.RequestLimit',],
}