首页 技术 正文
技术 2022年11月12日
0 收藏 423 点赞 2,089 浏览 3894 个字

1 绪言

  权限判定之后的下一个环节是访问频率控制,本篇我们分析访问频率控制部分源码。

2 源码分析

访问频率控制在dispatch方法中的initial方法调用check_throttles方法开始。入口如下:

def check_throttles(self, request):    for throttle in self.get_throttles():#遍历每一个频率控制对象        if not throttle.allow_request(request, self):            self.throttled(request, throttle.wait())#wait方法返回还需要等待多少秒才可以访问

get_throttles是获取所有的频率控制类的实例对象,源码如下:

def get_throttles(self):        return [throttle() for throttle in self.throttle_classes]

获取和实例化的方法都是通过列表生成式和读取配置的频率控制类,与认证、权限如出一辙,这里不再赘述。关键过程在执行实例化对象里的方法,这里以rest_framework自带的SimpleRateThrottle类为例进行分析。check_throttles方法内的for循环开始后,首先获取一个频率控制实例,然后执行allow_request方法:

def allow_request(self, request, view):    if self.rate is None:#如果配置中设置的频率是None,就是不限制访问频率,直接返回True        return True    #get_cache_key的作用是从request中获取访问端标识(例如用户名、IP)    #这个方法必须被之类覆写    self.key = self.get_cache_key(request, view)    if self.key is None:        return True    #下面的cache是django自带的缓存    #从缓存中取出访问记录(一个列表),如果找不到(没有访问过)就赋值为一个空列表    self.history = self.cache.get(self.key, [])    self.now = self.timer()#获取当前时间    #如果有访问记录,先删除在访问时间段之外的记录    # 以3/m为例,时间段为1分钟,那么就是删除一分钟以前的记录    while self.history and self.history[-1] <= self.now - self.duration:        self.history.pop()    #如果剩余的访问记录数量多于访问最大频次(前一分钟访问次数超过3次)    if len(self.history) >= self.num_requests:        return self.throttle_failure()#不能再访问了   return self.throttle_success()#继续访问吧

allow_request方法内的self.rate属性是在构造方法中设置的,构造方法如下:

def __init__(self):        if not getattr(self, 'rate', None):#如果没有rate属性            self.rate = self.get_rate()#获得配置好的频率,形如:'3/m'        #对频率(例如’3/m')进行解析,分割成频次3,和时间间隔m        self.num_requests, self.duration = self.parse_rate(self.rate)

get_rate方法:

def get_rate(self):        if not getattr(self, 'scope', None):#如果没有设置scope属性就抛出异常            msg = ("You must set either `.scope` or `.rate` for '%s' throttle" %                   self.__class__.__name__)            raise ImproperlyConfigured(msg)        try:#如果设置了scope,就去配置中通过scope取出这个配置            #THROTTLE_RATES是在settings.py中的频率控制配置项,是一个字典            return self.THROTTLE_RATES[self.scope]#返回配置好的频率,形如:'3/m'        except KeyError:            msg = "No default throttle rate set for '%s' scope" % self.scope            raise ImproperlyConfigured(msg)

parse_rate方法:

def parse_rate(self, rate):        if rate is None:            return (None, None)        # 配置中设置的频率格式为:’3/m'        num, period = rate.split('/')        num_requests = int(num)        #获取时间间隔,s为秒,m为分        duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]        return (num_requests, duration)#返回一个tuple

那么,此时allow_request的第一行代码就成功获得了配置好的频率。之所以要把get_rate和parse_rate方法源码贴出来,是因为方法里面出现了scope属性,这个属性配置用户配置我们的频率,例如我们要配置一分钟访问三次,则在我们自定义的类中首先需要给scope一个字符串值,例如scope=“xxx” , 然后在settings.py中进行如下配置:

REST_FRAMEWORK = {    'DEFAULT_THROTTLE_RATES': {        'xxx': '3/m',    },
}

另外,allow_request中调用了一个get_cache_key方法,该方法的作用是获取访问端的标识,这个方法必须被覆写,否则会抛出异常。

继续贴出接受访问和拒绝访问时执行的方法源码:

def throttle_success(self):    # 如果可以访问,就将当前时间加入到缓存中    self.history.insert(0, self.now)    self.cache.set(self.key, self.history, self.duration)    return True#返回True标识可以访问
def throttle_failure(self):    return False#返回False表示拒绝访问

  至于在allow_request方法中如何进行访问判断,在代码中有详细注释。

在退出allow_request方法后,如果被拒绝,最初被执行的check_throttles方法会调用一个wait方法,这个方法返回的是还有多少秒可以访问。

3 自定义频率控制类

  方法一:完全自己重新写一个频率控制类

import timeVISIT_RECORD = {} #存放IP的数据库  可以放在缓存!class VisitThrattle(object):    def __init__(self):        self.history = None     def allow_request(self, request, view):        remote_addr = request._request.META.get('REMOTE_ADDR')#获取IP        ctime = time.time()#当前时间        if remote_addr not in VISIT_RECORD:            VISIT_RECORD[remote_addr] = [ctime,]  #表示第一次访问            return True        history = VISIT_RECORD.get(remote_addr)        self.history = history        while history and history[[-1] < ctime -60:            history.pop()        if len(history) < 3:            history.insert(0, ctime)            return True        return False

  方法二:继承django rest_framework中的类

  根据IP进行频率控制:

class VisitThrottle(SimpleRateThrottle):  #对匿名用户的ip号通过时间做访问频率控制    scope = 'IPScope'       def get_cache_key(self, request, view):  #去缓存里取数据        return self.get_ident(request)#这是BaseThrottle中的方法

根据用户名进行频率控制:

class UserThrottle(SimpleRateThrottle):   #对用户的名字 通过时间做访问频率控制    scope = "userScope"    def get_cache_key(self, request, view):          return request.user.username

4 频率控制配置

  在settings.py文件中配置DEFAULT_THROTTLE_RATES,DEFAULT_THROTTLE_RATES里面的键必须与频率控制类里面的scope的值一一对应。:

REST_FRAMEWORK = {
……
'DEFAULT_THROTTLE_RATES': { 'IPScope': '3/minute', 'userScope': '3/minute'
}
}

  然后配置DEFAULT_THROTTLE_CLASSES,有全局配置和局部配置之分,全局配置在settings.py文件中进行,局部配置在视图配种进行,配制方法与认证类、权限类的方法一直,这里不再介绍。

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,031
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,520
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,368
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,148
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,781
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,859