django restframework框架四 截流

@(python之路)[django restframework框架四 截流]
django restframework框架四 截流

截流简介

 用户的访问频率控制。我们把一个人访问的事件按戳添加列表中,或者是根据ip计数。例如:一分钟访问三次,过一分钟pop一次。

截流组件

这里我们把截流组件拿出来。以后用得时候可以直接导入取用。
我们写的也是参考源码。


from rest_framework.throttling import SimpleRateThrottle

class UserRateThrottle(SimpleRateThrottle):
    scope = 'user'
    def get_cache_key(self, request, view):
        if request.user:
            # 如果已经登录,pk
            ident = request.user
        else:
            # 如果没有登录,IP
            ident = self.get_ident(request)
        # 'throttle_%(scope)s_%(ident)s'
        #  throttle_user_fengfeng
        return self.cache_format % {
            'scope': self.scope,
            'ident': ident
        }

    def allow_request(self, request, view):
        if request.auth.user.user_type == 1:
            # self.num_requests = 3
            # self.duration = 60
            pass
        else:
            self.num_requests = 6
        return super(UserRateThrottle,self).allow_request(request, view)

配置文件添加
添加如下这行:


# 此缓存将内容保存至文件
# 配置:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': '/var/tmp/django_cache',
    }
}
# 注:其他配置同开发调试版本


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

在调用缓存得时候,是调用得源码中

def allow_request(self, request, view):
    if self.rate is None:
        return True

    self.key = self.get_cache_key(request, view)
    if self.key is None:
        return True
	# 这里我们得history开始时空列表,随着用户得访问,我们将用户得时间戳添加近列表;
	# 等过一定时间,pop调一个。
    self.history = self.cache.get(self.key, [])
    self.now = self.timer()
    while self.history and self.history[-1] <= self.now - self.duration:
        self.history.pop()
    if len(self.history) >= self.num_requests:
        return self.throttle_failure()
    return self.throttle_success()

注意:这不是绝对得限制,我们可以针对注册用户做限制,匿名用户只能做,ip限制。限制也不是绝对得。
缓存配置文件

源码分析

我们 还是从dispatch进入主流程,看他的initial.
1

 def initial(self, request, *args, **kwargs):
        self.format_kwarg = self.get_format_suffix(**kwargs)
        neg = self.perform_content_negotiation(request)
        request.accepted_renderer, request.accepted_media_type = neg
        version, scheme = self.determine_version(request, *args, **kwargs)
        request.version, request.versioning_scheme = version, scheme
        self.perform_authentication(request)
        self.check_permissions(request)
        # 截流频率
        self.check_throttles(request)

 这里就是截流具体要做的东西self.check_throttles(request),具体是怎么做的,我们接着看。
2

def check_throttles(self, request):
     for throttle in self.get_throttles():
	     # 是否允许访问(allow_request)。如果不允许访问,就会抛出异常。
         if not throttle.allow_request(request, self):
	         # 我们注意的是throttle.wait() 他是提示多久以后才可以访问
             self.throttled(request, throttle.wait())

这里的self.get_throttles()还是个列表生成式,在里面self.throttle_classes这里边有它的默认配置。

throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES

在我们使用的时候需要导入

from rest_framework.throttling import BaseThrottle

源码分析:
3

class BaseThrottle(object):
    def allow_request(self, request, view):
	    pass
    def get_ident(self, request):
        xff = request.META.get('HTTP_X_FORWARDED_FOR')
        remote_addr = request.META.get('REMOTE_ADDR')
		    ……
    def wait(self):
		pass

HTTP_X_FORWARDED_FOR这里拿的是请求相关信息。
REMOTE_ADDR拿的是ip。
4

# 匿名
class AnonRateThrottle(SimpleRateThrottle)

# 用户
class UserRateThrottle(SimpleRateThrottle)

# 范围
class ScopedRateThrottle(SimpleRateThrottle)

例子:

from rest_framework.throttling import SimpleRateThrottle
class UserView(APIView):
    authentication_classes = [MyAuthtication,]
    throttle_classes = [BaseThrottle,]
    def get(self,request,*args,**kwargs):
        self.dispatch
        return HttpResponse("get")
    def post(self,request,*args,**kwargs):
        return HttpResponse("post")
    def put(self,request,*args,**kwargs):
        return HttpResponse("put")
    def delete(self,request,*args,**kwargs):
        return HttpResponse("delete")

 当我们这么做的时候(throttle_classes = [BaseThrottle,]),他会先做一步实例化。具体请看2他是这样做的实例化。他会执行__init__.py具体看一下:

class SimpleRateThrottle(BaseThrottle):
    cache = default_cache
    timer = time.time
    cache_format = 'throttle_%(scope)s_%(ident)s'
    scope = None
    
    # DEFAULT_THROTTLE_RATES 定义访问频率的。
    THROTTLE_RATES = api_settings.DEFAULT_THROTTLE_RATES
    def __init__(self):
	   
        if not getattr(self, 'rate', None):
            # 这里我们要具体分析get_rate具体做了什么。
            self.rate = self.get_rate()
        self.num_requests, self.duration = self.parse_rate(self.rate)
    def get_rate(self):
        if not getattr(self, 'scope', None):
            msg = ("You must set either `.scope` or `.rate` for '%s' throttle" %
                   self.__class__.__name__)
            raise ImproperlyConfigured(msg)

        try:
	        # 找到我们的scope,scope=None
            return self.THROTTLE_RATES[self.scope]
        except KeyError:
            msg = "No default throttle rate set for '%s' scope" % self.scope
            raise ImproperlyConfigured(msg)

根据他在配置文件中添加得user:1/3我们可以分析它的源码

class SimpleRateThrottle(BaseThrottle):
    def parse_rate(self, rate):
        """
        Given the request rate string, return a two tuple of:
        <allowed number of requests>, <period of time in seconds>
        """
        if rate is None:
            return (None, None)
        num, period = rate.split('/')
        num_requests = int(num)
        duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]
        return (num_requests, duration)

他是在这里做的处理;具体流程我们还需要在SimpleRateThrottle类中具体看一下,这里不叫简单不在做详细得解释。
若有不懂得同学,可以留言。

posted @ 2018-06-04 14:56  zz小公子  阅读(150)  评论(0编辑  收藏  举报