SimpleRateThrottle频率控制类,继承了BaseThrottle , 添加和重写了一些方法 , 重点是添加了get_cache_key 方法 , 但必须自己实现该方法class SimpleRateThrottle(BaseThrottle):# 限流需要用到缓存 , 使用drf默认的缓存# 如果其他继承类想修改缓存机制 , cache = caches['缓存名'] 进行修改cache = default_cache# time.time方法 , 但是并没有()进行实例调用# 类似计时器功能 , 在这里留好 , 后续调用timer = time.time# 缓存设置 , 字符串格式化方法后续传参使用cache_format = 'throttle_%(scope)s_%(ident)s'# scope默认没有设置,该值是DEFAULT_THROTTLE_RATES中对应限流类的keyscope = None# 限流频率默认的配置值THROTTLE_RATES = api_settings.DEFAULT_THROTTLE_RATESdef __init__(self):if not getattr(self, 'rate', None):# 从下面get_rate()方法获取访问频率限制的参数self.rate = self.get_rate()# 通过self.parse_rate方法获取限制的频率及持续时间赋值给num_requestsself.num_requests, self.duration = self.parse_rate(self.rate)# 获取当前请求的标识def get_cache_key(self, request, view):raise NotImplementedError('.get_cache_key() must be overridden')# 获取settings频率设置限流类对应的keydef get_rate(self):# 如果没有scope , 抛出异常if not getattr(self, 'scope', None):msg = ("You must set either `.scope` or `.rate` for '%s' throttle" %self.__class__.__name__)raise ImproperlyConfigured(msg)try:# 从 self.THROTTLE_RATES 中获取设置的scopereturn self.THROTTLE_RATES[self.scope]except KeyError:msg = "No default throttle rate set for '%s' scope" % self.scoperaise ImproperlyConfigured(msg)# 获取限流频率设置及持续时间def parse_rate(self, rate):# 如果没有设置频率限制 , 直接返回Noneif rate is None:return (None, None)# 在settings设置频率我们使用 num/type 设置值# 字符串使用/分割 , 获取两个对应的值num, period = rate.split('/')num_requests = int(num)#settings中设置时间单位以天为单位可以是day也可以是d# period[0]获取第一个字符为key , 以秒为单位换算 , 秒就1 , 分就是60 , 天就是86400# 如果需要扩展月、年等时间,可以扩展源码duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]# 返回频率和持续时间return (num_requests, duration)# 是否允许请求通过 , 运行返回True , 否则返回Falsedef allow_request(self, request, view):# 如果没有设置限流频率 , 直接返回Trueif self.rate is None:return True# 获取用户标识赋值给self.keyself.key = self.get_cache_key(request, view)# 没有用户标识直接返回Trueif self.key is None:return True# 获取历史访问时间戳self.history = self.cache.get(self.key, [])# 获取当前时间戳self.now = self.timer()# while循环 , 如果历史访问时间戳有值 , 拿到历史时间戳[-1]的数据 , 如果小于等于当前时间戳减去持续时间 , 弹出最后一个时间戳# 当前时间-持续时间 , 就相当于需要限制的时间区间 , 如果历史时间戳小于等于该区间 , 才不会继续popwhile self.history and self.history[-1] <= self.now - self.duration:self.history.pop()# 如果历史访问时间戳的列表长度大于等于我们设置频率数量 , 说明到了频率上限if len(self.history) >= self.num_requests:# 返回self.throttle_failure 对应Falsereturn self.throttle_failure()# 返回self.throttle_success 对应Truereturn self.throttle_success()# 频率未到达上限时返回该方法def throttle_success(self):# 在历史请求时间戳列表 , 将当前时间插入该列表self.history.insert(0, self.now)# 更新缓存内容self.cache.set(self.key, self.history, self.duration)# 返回Truereturn True# 频率到达上限时返回该方法def throttle_failure(self):return False# 返回还需要多长时间可以进行下一次请求 , 可选方法def wait(self):if self.history:# 如果历史请求时间戳有值 , 剩余时间等于持续时间减去(当前时间-第一次请求)remaining_duration = self.duration - (self.now - self.history[-1])else:# 剩余的时间等于持续时间remaining_duration = self.duration# 允许请求的次数 等于 允许的次数-已请求的次数+1available_requests = self.num_requests - len(self.history) + 1# 如果允许请求的次数小于等于0 , 返回Noneif available_requests <= 0:return Nonereturn remaining_duration / float(available_requests)
经验总结扩展阅读
- 微服务组件--限流框架Spring Cloud Hystrix分析
- b站限流是什么意思
- 网上的限流是什么意思
- 电信限速不限量套餐 电信不限量套餐是无限流量吗?
- 头条被限流了怎么办?
- 一个手机2个抖音号会限流吗?
- 抖音连续点赞会被限流是什么意思?
- 抖音显示你的视频专属口令是被限流了吗?
- 快手为什么会被限流?
- 抖音连着点赞限流是什么意思?