from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.throttling import SimpleRateThrottle, BaseThrottle from rest_framework import exceptions # 頻率控制類--> 比較好的是,能夠自由控制訪問頻率 class Throttle(SimpleRateThrottle): scope = 'least_throttle' # 指向的是settings.py中設置的訪問頻率 def get_cache_key(self, request, view): return self.get_ident(request) # 該方法獲取的是前端發來請求的用戶的惟一標識,此處是ip
# 自定義頻率類 --> 自定義的,相對較靈活,比較很差的是訪問頻率單一,修改起來比較麻煩 class MyThrottle(BaseThrottle): VISIT_RECORD = {} def __init__(self): self.history = None def allow_request(self, request, view): # 自定義控制每分鐘訪問多少次,運行訪問返回true,不容許訪問返回false # (1)取出訪問者ip{ip1:[第二次訪問時間,第一次訪問時間],ip2:[]} # (2)判斷當前ip不在訪問字典裏,若是不在添加進去,而且直接返回True,表示第一次訪問,在字典裏,繼續往下走 # (3)循環判斷當前ip的列表,有值,而且當前時間減去列表的最後一個時間大於60s,把這種數據pop掉,這樣列表中只有60s之內的訪問時間, # (4)判斷,當列表小於3,說明一分鐘之內訪問不足三次,把當前時間插入到列表第一個位置,返回True,順利經過 # (5)當大於等於3,說明一分鐘內訪問超過三次,返回False驗證失敗 # (1)取出訪問者ip # print(request.META) # 取出訪問者ip ip = request.META.get('REMOTE_ADDR') import time # 拿到當前時間 ctime = time.time() # (2)判斷當前ip不在訪問字典裏,添加進去,而且直接返回True,表示第一次訪問 if ip not in self.VISIT_RECORD: self.VISIT_RECORD[ip] = [ctime, ] return True # 是個當前訪問者ip對應的時間列表 [第一次訪問的時間,] self.history = self.VISIT_RECORD.get(ip) # (3)循環判斷當前ip的列表,有值,而且當前時間減去列表的最後一個時間大於60s,把這種數據pop掉,這樣列表中只有60s之內的訪問時間, while self.history and ctime - self.history[-1] > 60: self.history.pop() # (4)判斷,當列表小於3,說明一分鐘之內訪問不足三次,把當前時間插入到列表第一個位置,返回True,順利經過 # (5)當大於等於3,說明一分鐘內訪問超過三次,返回False驗證失敗 if len(self.history) < 3: self.history.insert(0, ctime) return True else: return False
# Create your views here. class Books(APIView): throttle_classes = [Throttle, ] # 繼承SimpleRateThrottle的控制類 # throttle_classes = [MyThrottle, ] # 自定義頻率控制類 """ # 源代碼中,當超過訪問頻率的時候,會返回一條detail數據,而內容信息是英文的,此處想將其改成中文, # 下面的代碼只是改了前一部分的內容,後面一部份內容並無修改爲功 detail = '您的訪問頻率過高,請等一等啊!' def throttled(self, request, wait): raise exceptions.Throttled(wait, detail=self.detail) """ def get(self, request): return Response('ok')