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)}

推薦閱讀