7-1 频率-DRF限制频率

目录:

  • 节流的介绍
  • SimpleRateThrottle 源码分析
  • 自定义限制频率(节流)

一、节流介绍

  开放平台的API接口调用需要限制其频率,以节约服务器资源和避免恶意的频繁调用。其实有的时候我们辛辛苦苦造的数据被爬虫份子给爬掉。爬虫在爬数据的时候数据量也比较大,那么这个时候就会给我们服务器造成了压力,影响用户的使用。在这个时候我们就要限制用户的使用频率。那怎么限制呐?我们给出一些限制的思路:

  节流思路:

    我现在想 限制 每个用户  1分钟之内 只能访问 3次(3/min),并且每个用户在访问的时候,我按一定的规则记录当前用户访问的记录,比如我按 ip地址记录:

    {"127.0.0.1": {"12:29:50","12:29:40","12:29:20'"}}:指的是 我 127.0.0.1 ip地址在1分钟之内访问 3次。这个时候我在  12:30:10 去访问时,在1分钟之内,很明显无法访问。

    那我如果是 12:30:21 去访问,这个时候 12:30:21 跟 {"127.0.0.1": {"12:29:50","12:29:40","12:29:20'"}} 中最后一个值 12:29:20 比,大于1分钟了,这个时候可以访问了。

         那个这个时候 列表就变成:  {"127.0.0.1": {"12:30:21","12:29:50","12:29:40"}} 就把 12:30:21 加到列表中第一个参数,把 12:29:20列表中删除掉。

    依次类推...

二、SimpleRateThrottle 源码分析

2.1、导入 SimpleRateThrottle

from rest_framework.throttling import SimpleRateThrottle

2.2、查看源码

Ctrl + SimpleRateThrottle -> BaseThrottle

发现它是继承一个基础类  Ctrl + BaseThrottle ,有哪些东西:

class BaseThrottle(object):
    """
    Rate throttling of requests.
    """

    def allow_request(self, request, view):  #必须要实现的1个方法,True:允许访问  False:禁止访问
        """
        Return `True` if the request should be allowed, `False` otherwise.
        """
        raise NotImplementedError('.allow_request() must be overridden')

    def get_ident(self, request):
        .....

    def wait(self):
        .....

好啦,我们再来看看 SimpleRateThrottle 类:发现有一个 scope = None 属性,这个属性是要配置的。为什么呐?因为 它要去读取限制用户到底多长时间读取一次。

2.3、内置节流类

说明:我们来看看 我们内置的节流类有哪些,他们跟SimpleRateThrottle源码在一个文件中

class AnonRateThrottle(SimpleRateThrottle):
    """
    限制匿名用户
    """
    scope = 'anon'

    def get_cache_key(self, request, view):
        if request.user.is_authenticated:
            return None  # Only throttle unauthenticated requests.

        return self.cache_format % {
            'scope': self.scope,
            'ident': self.get_ident(request)   #获取IP地址
        }


class UserRateThrottle(SimpleRateThrottle):
    """
    限制已认证用户
    """
    scope = 'user'

    def get_cache_key(self, request, view):
        if request.user.is_authenticated:
            ident = request.user.pk    #用户主键当标识
        else:
            ident = self.get_ident(request)

        return self.cache_format % {
            'scope': self.scope,
            'ident': ident
        }


class ScopedRateThrottle(SimpleRateThrottle):
    """
    每个用户对视图的访问次数
    """
    scope_attr = 'throttle_scope'

    def __init__(self):
        # Override the usual SimpleRateThrottle, because we can't determine
        # the rate until called by the view.
        pass

    def allow_request(self, request, view):
        # We can only determine the scope once we're called by the view.
        self.scope = getattr(view, self.scope_attr, None)

        # If a view does not have a `throttle_scope` always allow the request
        if not self.scope:
            return True

        # Determine the allowed request rate as we normally would during
        # the `__init__` call.
        self.rate = self.get_rate()
        self.num_requests, self.duration = self.parse_rate(self.rate)

        # We can now proceed as normal.
        return super(ScopedRateThrottle, self).allow_request(request, view)

    def get_cache_key(self, request, view):
        """
        If `view.throttle_scope` is not set, don't apply this throttle.

        Otherwise generate the unique cache key by concatenating the user id
        with the '.throttle_scope` property of the view.
        """
        if request.user.is_authenticated:
            ident = request.user.pk
        else:
            ident = self.get_ident(request)

        return self.cache_format % {
            'scope': self.scope,
            'ident': ident
        }
内置的节流类

源码已经搞好啦。

三、自定义限制频率(节流)

3.1、新建内置频率类

说明:在应用下新建一个throttlings文件。创建频率类:

from rest_framework.throttling import SimpleRateThrottle


class VisitThrottle(SimpleRateThrottle):
    scope = "未认证用户"
  
    def get_cache_key(self, request, view):
        return  self.get_ident(request)   #ip地址当做key,可以会缓存到django的缓存里面
        
 
class UserThrottle(SimpleRateThrottle):
    scope = "已认证用户"
  
    def get_cache_key(self, request, view):  #要写一个认证方法,告诉人家你拿什么当key
        return  request.user  #当前登录用户当做key

好了,频率类 新建好了。

3.2、全局配置

说明:在settings.py的REST_FRAMEWORK 下配置全局。

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': ....,
    'DEFAULT_PERMISSION_CLASSES': ...,
    'DEFAULT_THROTTLE_CLASSES': ['app05.throttlings.UserThrottle', ],
    'DEFAULT_THROTTLE_RATES': {
        '未认证用户': '3/m',
        '已认证用户': '10/m',
    },
}

意思是:未认证用户 1分钟3次,认证用户是 1分钟10次。那这个时间定义在哪里定义的呐?SimpleRateThrottle源码中有,我们来看看:

class SimpleRateThrottle(BaseThrottle):
    """
    ...
    Period should be one of: ('s', 'sec', 'm', 'min', 'h', 'hour', 'd', 'day')  #时间设置
    ....
    """
    ....

3.3、局部配置

说明:上面是全局配置,但是有的时候我不想全局的,我只想局部实现,那咋办呐?

....
from .throttlings import VisitThrottle  #导入自定义频率类

# Create your views here.


class CartView(APIView):

    # 节流 局部配置
    throttle_classes = [VisitThrottle]

    def get(self, request, *args, **kwargs):

        ....
        return JsonResponse(ctx)

但是全局也写了,我只想在视图中什么限制也不想加,那我们可以是  throttle_classes 为空就行了,如下:

class CartView(APIView):

    # 视图不加任何限制,但是全局已经配置了
    throttle_classes = []

    ...

3.4、测试结果

1、已认证用户

 

2、未认证用户

posted @ 2020-04-29 11:22  帅丶高高  阅读(278)  评论(0)    收藏  举报