django_restfreamwork 6 限流元件
阿新 • • 發佈:2020-08-22
DRF【限流元件】
作用和原理
作用:開放平臺API介面的呼叫需要限制其頻率,節約伺服器避免惡意頻繁呼叫
正常使用者,一分鐘訪問3-5次,如果是指令碼惡意可能一分鐘訪問10次以上
自定義限流策略
舉例:以IP地址作為限流(最常用)
構建訪問列表
需要構造訪問列表 key為ip,value則為[訪問時間1,訪問時間2,訪問時間3]
限流策略
- 1,獲取ip地址
- 2,判斷ip地址是否在IP的訪問列表中
- 如果不在訪問列表中,將這個ip新增到訪問列表中,新增一條記錄:
ip:[訪問的時間1,]
- 如果在訪問列表中(之前訪問過),將這個ip當前訪問的時間加入到value的列表中:
ip:[訪問時間1,訪問時間2]
- 如果不在訪問列表中,將這個ip新增到訪問列表中,新增一條記錄:
- 3,
時間判斷
:確保列表中這個ip的最新的訪問時間
和最老的訪問時間
之間的時間差是 自定義時間之內(比如1分鐘之內) - 4,
次數判斷
:得到列表的長度,判斷是否是允許的次數,判斷某段時間內,訪問次數超過多少次,做限流
新建 throttle.py ,也可以新建在utils/throttle.py 中
throttle.py 作為自定義限流元件
比如策略為 60秒之內,同一個IP請求超過3次,做限流
from rest_framework.throttling import BaseThrottle import time VISIT_RECORD = {} #預設訪問列表 class MyThrottle(BaseThrottle): def __init__(self): self.history = None def allow_request(self, request, view): """ 實現限流的邏輯 以IP限流(最常用) 訪問列表 key為ip,value則為[訪問時間1,訪問時間2,訪問時間3] {IP: [訪問時間1, 訪問時間2, 訪問時間3]} """ # 1, 獲取請求的IP地址 ip = request.META.get("REMOTE_ADDR") # 2,判斷IP地址是否在訪問列表 now = time.time() if ip not in VISIT_RECORD: #如果不在訪問列表中,證明第一次訪問 VISIT_RECORD[ip] = [now,] # 不限流直接return True return True # 如果在訪問列表,則先拿出這個ip的歷史記錄 history = VISIT_RECORD[ip] history.insert(0, now) #插入列表最前面0號角標,也可以插入到最後面-1 # 3,時間頻率:確保列表裡最新訪問時間以及最老的訪問時間差 是1分鐘(60秒) while history and history[0] - history[-1] > 60: history.pop() self.history = history # 4,次數頻率:得到列表長度,判斷是否是允許的次數 if len(history) > 3: """60秒之內同一個IP請求3次以上,做限流""" return False else: return True def wait(self): """ 返回需要再等多久才能訪問 """ time = 60 - (self.history[0] - self.history[-1]) return time
對指定介面做限流策略
views.py
# from .models import Book # from rest_framework.views import APIView # from rest_framework.response import Response # from .serializers import BookSerializer # from rest_framework.permissions import IsAuthenticated from .throttle import MyThrottle #匯入自定義限流類 # class BookView(APIView): throttle_classes = [MyThrottle] #對這個介面 自定義限流策略 # def get(self, request): # book_list = Book.objects.all() # ret = BookSerializer(book_list, many=True) # return Response(ret.data)
序列化器忽略
測試訪問限流策略
60秒內前三次重新整理頁面都可以獲取資料,第4次開始介面返回了限流提示
框架預設限流策略
重寫get_catch_key
新建 throttle.py ,也可以新建在utils/throttle.py 中
throttle.py 作為框架限流元件
類繼承SimpleRateThrottle
並重寫 get_cache_key
from rest_framework.throttling import SimpleRateThrottle
class MyThrottle(SimpleRateThrottle):
"""
scope的值要和settings中配置的值要相同才會生效
"""
scope = "aaa" #限流策略名
def get_cache_key(self, request, view):
"""
需要重寫 get_cache_key ,因為父類的 get_cache_key 會拋異常
重寫只需返回什麼(比如ip),就按照什麼策略進行限流
"""
key = self.get_ident(request) #框架中 self.get_ident會獲取ip地址
return key
配置訪問頻率
settings.py中新增配置
settings中key訪問策略名 aaa
和配置中頻率的 key aaa
要一樣,才會生效
#REST_FRAMEWORK = {
#jwt登入認證
....
....
# 頻率元件
"DEFAULT_THROTTLE_RATES":{
#key為訪問策略名,value為允許次數/週期(週期寫法 s|m|h|d s代表1秒,m代表1分鐘,h代表1小時,d代表1天)
"aaa":"3/m" #頻率:每分鐘3次
},
#}
對指定介面進行限流策略
# from .models import Book
# from rest_framework.views import APIView
# from rest_framework.response import Response
# from .serializers import BookSerializer
# from rest_framework.permissions import IsAuthenticated
from .throttle import MyThrottle #匯入框架的限流策略
# class BookView(APIView):
throttle_classes = [MyThrottle] #對這個介面 框架的限流策略
# def get(self, request):
# book_list = Book.objects.all()
# ret = BookSerializer(book_list, many=True)
# return Response(ret.data)
序列化器忽略
測試訪問限流策略
訪問介面第4次 被限流