45.限流Throttling及源码解析( 二 )

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)AnonRateThrottle匿名限流类:继承了SimpleRateThrottle,重写了 get_cache_key 方法AnonRateThrottle 只会限制未经身份验证的用户 。传入的请求的IP地址用于生成一个唯一的密钥 。允许的请求频率由以下各项之一确定(按优先顺序):

  1. 类的 rate 属性,可以通过继承 AnonRateThrottle 并设置该属性来修改这个值,优先级高
  2. settings配置文件中 DEFAULT_THROTTLE_RATES['anon'] 配置项的值 。优先级低
  3. anonratetrottle 适用于想限制来自未知用户的请求频率的情况
class AnonRateThrottle(SimpleRateThrottle):# 设置频率控制的key为anonscope = 'anon'# 重写get_cache_key方法def get_cache_key(self, request, view):# 如果请求用户是经过认证的用户 , 不需要进行限流,直接返回Noneif request.user.is_authenticated:return None# 如果用户是未经认证的用户,将该类的scope和 用户的IP地址传入SimpleRateThrottle的self.cache_format类属性return self.cache_format % {'scope': self.scope,'ident': self.get_ident(request)}

推荐阅读