1. 程式人生 > 實用技巧 >django_restfreamwork 6 限流元件

django_restfreamwork 6 限流元件

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]
  • 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次 被限流