目录
一、实现自定义访问频率控制逻辑 - BaseThrottle
二、DRF 内置频率类 - SimpleRateThrottle
四、频率错误信息的中文显示 - 即 throttled 方法重写
一、实现自定义访问频率控制逻辑 - BaseThrottle
1-1 访问频率实现思路(一个ip一分钟只能访问3次)
- 取出访问者ip - request.MATE.get('REMOTE_ADDR ')
- 第一次访问:判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问 - {‘ip1’:[time1,]}
- 非第一次访问:判断当前ip在访问字典里,继续往下走 - {‘ip1’:[time1,time2]}
- 循环当前ip的列表,若非空,则取出符合 当前时间 - 列表末尾时间 > 60s 的对象时间,进行pop删除操作。- 保证列表中只存在未超过间隔60s的访问时间
- 判断操作 :
- 当列表长度<3 - 一分钟内访问不超过三次,将当前时间插入列表第一位,返回True,表示验证成功
- 当列表长度>3 - 一分钟内访问次数唱过三次,返回False,表示验证失败
1-2 访问频率逻辑实现
总结:
- 频率类
- 必须重写allow_request(self, request, view) 方法
- 若频率验证通过 : 返回True
- 若频率验证不通过:返回False
- 必须重写 wait 方法用于频率验证不通过之后等待
- 视图类
- 局部使用 - throttle_classes = [drfAuth.MyThrottle, ]
''' drfAuth.py - 基于DRF的自定义频率实现 ''' import time class MyThrottle(): # 用于存放ip列表 visitor_dic = {} def __init__(self): self.history = None def allow_request(self, request, view): # MATA:请求header内数据 # REMOTE_ADDR:获取ip地址 ip = request.META.get('REMOTE_ADDR') ctime = time.time() # 不在字典中 - 第一次访问 if ip not in self.visitor_dic: self.visitor_dic[ip] = [ctime, ] return True # 根据当前访问者ip,取出访问的时间列表 history = self.visitor_dic[ip] self.history = history # history[-1]:访问时间列表最后一个 while history and ctime - history[-1] > 60: history.pop() if len(history) < 3: # 把当前时间放到第0个位置上 history.insert(0, ctime) return True return False # 若前方频率范围Flase则60s后才能进行操作 def wait(self): # 剩余时间 ctime = time.time() return 60 - (ctime - self.history[-1]) ''' view视图函数 ''' class FrequencyTest(APIView): throttle_classes = [drfAuth.MyThrottle, ] def get(self, request): return HttpResponse('get') def post(self, request): return HttpResponse('post')
1-3 源码分析
''' check_throttles APIView - dispatch - initial - check_throttles ''' def check_throttles(self, request): """ Check if request should be throttled. Raises an appropriate exception if the request is throttled. 检查是否应控制请求。如果控制了请求,则引发适当的异常。 """ for throttle in self.get_throttles(): # 判断指定对象内是否存在allow_request,必须传入request,和基于APIView的试图类 # 所以,在自己的频率控制中,返回必须为True or False if not throttle.allow_request(request, self): # 若频率控制返回False 则执行类内的wait()方法抛出异常 self.throttled(request, throttle.wait()) ''' get_throttles ''' def get_throttles(self): """ Instantiates and returns the list of throttles that this view uses. 实例化并返回视图使用的节流阀列表。 """ return [throttle() for throttle in self.throttle_classes] ''' throttled ''' def throttled