返回顶部

DRF之频率

一. DRF频率

  开放平台的API接口调用需要限制其频率,以节约服务器资源和避免恶意的频繁调用。

1. 频率组件原理

DRF中的频率控制基本原理是基于访问次数和时间的,当然我们可以通过自己定义的方法来实现。

当我们请求进来,走到我们频率组件的时候,DRF内部会有一个字典来记录访问者的IP,

以这个访问者的IP为key,value为一个列表,存放访问者每次访问的时间,

{  IP1: [第三次访问时间,第二次访问时间,第一次访问时间],}

把每次访问最新时间放入列表的最前面,记录这样一个数据结构后,通过什么方式限流呢~~

如果我们设置的是10秒内只能访问5次,

  -- 1,判断访问者的IP是否在这个请求IP的字典里

  -- 2,保证这个列表里都是最近10秒内的访问的时间

      判断当前请求时间和列表里最早的(也就是最后的)请求时间的查

      如果差大于10秒,说明请求以及不是最近10秒内的,删除掉,

      继续判断倒数第二个,直到差值小于10秒

  -- 3,判断列表的长度(即访问次数),是否大于我们设置的5次,

      如果大于就限流,否则放行,并把时间放入列表的最前面。

 

2. 简单应用

自定义频率类,自己实现通过IP来限制访问频率:

from rest_framework.throttling import BaseThrottle,SimpleRateThrottle
import time
from rest_framework import exceptions

visit_record = {}
class VisitThrottle(BaseThrottle):
    # 限制访问时间
    VISIT_TIME = 10
    VISIT_COUNT = 3

    # 定义方法 方法名和参数不能变
    def allow_request(self, request, view):
        # 获取登录主机的id
        id = request.META.get('REMOTE_ADDR')
        self.now = time.time()

        if id not in visit_record:
            visit_record[id] = []

        self.history = visit_record[id]
        # 限制访问时间
        while self.history and self.now - self.history[-1] > self.VISIT_TIME:
            self.history.pop()
        # 此时 history中只保存了最近10秒钟的访问记录
        if len(self.history) >= self.VISIT_COUNT:
            return False
        else:
            self.history.insert(0, self.now)
            return True

    def wait(self):
        return self.history[-1] + self.VISIT_TIME - self.now

如果是以IP地址为key来限制流量的话,用DRF给我们提供的  SimpleRateThrottle 就可以做到了。

from rest_framework.throttling import SimpleRateThrottle

class VisitThrottle(SimpleRateThrottle):

    scope="visit_rate"
    def get_cache_key(self, request, view):

        return self.get_ident(request)

特别注意:

1.这个get_cache_key必须返回一个key,这个key默认用return self.get_ident(request)可以获得IP地址,就是以IP地址为key做限流。但是有些时候,需要用username做限制,就可以返回request.user.username。然后再全局配置,根据需求,假如除了登录用IP限制,其他业务视图用用户名限制,就可以这么配置。

 

只需要在登录视图加一个IP限制的类就可以了:

 

2.这个scope代表你的频率方法,在settings中配置:

全局使用

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
    "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",],
    "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",],
    "DEFAULT_THROTTLE_RATES":{
        "visit_rate":"5/m",
    }
}

局部使用

class TestView(APIView):

    authentication_classes = [MyAuth,]
    permission_classes = [MyPermission, ]
    throttle_classes = [VisitThrottle, ]

    def get(self, request):
        print(request.user)
        print(request.auth)
        # user_id = request.user.id

        return Response("认证测试")

 

posted @ 2020-10-14 21:41  muguangrui  阅读(66)  评论(0编辑  收藏  举报