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

浙公网安备 33010602011771号