DRF-访问频率配置(节流)

访问频率控制(节流)

  • 我们可以先编写一个类
class VisitThrottle(object):
    def allow_request(self, request, view):
        return True  # False表示访问频率太高被限制
    def wait(self):
        return None    
DRF-访问频率配置(节流)
微信截图_20190112111427
  • postman校验
DRF-访问频率配置(节流)
微信截图_20190112111522
DRF-访问频率配置(节流)
微信截图_20190112111555
  • 获取用户ip
class VisitThrottle(object):
    def allow_request(self, request, view):
        # 1. 获取用户ip
        remote_addr = request._request.META.get("REMOTE_ADDR")
        #print(remote_addr)

        ...
  • 添加访问记录
import time

# 存放访问记录(一般放数据库或者缓存中)
VISIT_RECORD = {}


class VisitThrottle(object):
    def allow_request(self, request, view):
        # 1. 获取用户ip
        remote_addr = request._request.META.get("REMOTE_ADDR")
        # print(remote_addr)
        # 2. 添加到访问记录中
        ctime = time.time()
        if remote_addr not in VISIT_RECORD:
            VISIT_RECORD[remote_addr] = [ctime, ]
            return True
        return False  # False表示访问频率太高被限制

    def wait(self):
        return None
DRF-访问频率配置(节流)
微信截图_20190112112710
  • 两种情况,之前说的是第一种,当用户没有访问的时候的情况,记录用户的访问记录的列表里面没有用户访问,但是如果用户已经访问,而我们需求是1分钟内只能访问3次,我们需要改进代码
class VisitThrottle(object):
    def allow_request(self, request, view):
        # 1. 获取用户ip
        remote_addr = request._request.META.get("REMOTE_ADDR")
        # print(remote_addr)
        # 2. 添加到访问记录中
        ctime = time.time()
        # 当VISIT_RECORD中没有这个记录,可以直接访问,添加一个记录
        if remote_addr not in VISIT_RECORD:
            VISIT_RECORD[remote_addr] = [ctime, ]
            return True
        history = VISIT_RECORD.get(remote_addr)
        # 拿到最后历史记录里面的最后一个时间,如果最后一个时间小于当前时间-60
        while history and history[-1] < ctime - 60:
            history.pop()
        if len(history) < 3:
            history.insert(0,ctime)
            return True

        return False  # False表示访问频率太高被限制

    def wait(self):
        return None
DRF-访问频率配置(节流)
微信截图_20190112113607
  • postman校验
DRF-访问频率配置(节流)
微信截图_20190112113637
  • wait返回的值是一个提示,表示多少秒以后可以访问
    def wait(self):
        return 10 # 写死了10秒
DRF-访问频率配置(节流)
微信截图_20190112120909
  • 在wait里面拿到访问记录
DRF-访问频率配置(节流)
微信截图_20190112121324
    def wait(self):
        """
        还需要等多少秒可以访问
        :return:
        """
        ctime = time.time()

        return 60 - (ctime - self.history[-1])

源码流程

内置控制频率的类

from rest_framework.throttling import BaseThrottle


class VisitThrottle(BaseThrottle):

    def __init__(self):
        self.history = None

    def allow_request(self, request, view):
        # 1. 获取用户ip
        remote_addr = request._request.META.get("REMOTE_ADDR")
        # print(remote_addr)
        # 2. 添加到访问记录中
        ctime = time.time()
        # 当VISIT_RECORD中没有这个记录,可以直接访问,添加一个记录
        if remote_addr not in VISIT_RECORD:
            VISIT_RECORD[remote_addr] = [ctime, ]
            return True
        history = VISIT_RECORD.get(remote_addr)
        self.history = history
        # 拿到最后历史记录里面的最后一个时间,如果最后一个时间小于当前时间-60
        while history and history[-1] < ctime - 60:
            history.pop()
        if len(history) < 3:
            history.insert(0, ctime)
            return True

        return False  # False表示访问频率太高被限制

    def wait(self):
        """
        还需要等多少秒可以访问
        :return:
        """
        ctime = time.time()
        return 60 - (ctime - self.history[-1])
DRF-访问频率配置(节流)
微信截图_20190112141225
  • 在SimpleRateThrottle里面
DRF-访问频率配置(节流)
微信截图_20190112141531
  • get_rate方法
DRF-访问频率配置(节流)
微信截图_20190112141649
  • get_rate方法返回值读取配置文件
DRF-访问频率配置(节流)
微信截图_20190112141713
  • 在我们自己继承的类里面写scpoe
DRF-访问频率配置(节流)
微信截图_20190112142138
  • settings配置
# 跟rest_有关的配置
REST_FRAMEWORK = {
    # "DEFAULT_AUTHENTICATION_CLASSES": ["myutils.auth.MyAuthtication"],
    "UNAUTHENTICATED_USER": lambda: "匿名用户哈哈",
    # "DEFAULT_PERMISSION_CLASSES": ["myutils.permission.MyPermission"],
    "DEFAULT_THROTTLE_RATES": {
        "myscope": '3/m'
    }

}
DRF-访问频率配置(节流)
微信截图_20190112142416
  • 我们设置的频率在源码里面传递
DRF-访问频率配置(节流)
微信截图_20190112142521
  • 3/m源码 m表示60
DRF-访问频率配置(节流)
微信截图_20190112142816
  • 回到构造函数
    def __init__(self):
        # 在构造方法里面,通过反射调用rate
        if not getattr(self, 'rate', None):
            # "3/m"
            self.rate = self.get_rate()
        #   3次 self.num_requests    60秒  self.duration
        self.num_requests, self.duration = self.parse_rate(self.rate)
  • 内部的allow_request方法
DRF-访问频率配置(节流)
微信截图_20190112143207
  • 使用ip作为我们的标识
class VisitThrottle(SimpleRateThrottle):
    scope = "myscope"

    def get_cache_key(self, request, view):
        return self.get_ident(request)
  • allow_request
    def allow_request(self, request, view):
        """
        Implement the check to see if the request should be throttled.

        On success calls `throttle_success`.
        On failure calls `throttle_failure`.
        """
        if self.rate is None:
            return True
        # 方法缓存里面
        self.key = self.get_cache_key(request, view)
        if self.key is None:
            return True
        # 去缓存里面拿到所有记录
        self.history = self.cache.get(self.key, [])
        # 获取当前时间
        self.now = self.timer()

        # Drop any requests from the history which have now passed the
        # throttle duration
        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()
  • settings配置
# 跟rest_有关的配置
REST_FRAMEWORK = {
    # "DEFAULT_AUTHENTICATION_CLASSES": ["myutils.auth.MyAuthtication"],
    "UNAUTHENTICATED_USER": lambda: "匿名用户哈哈",
    # "DEFAULT_PERMISSION_CLASSES": ["myutils.permission.MyPermission"],
    "DEFAULT_THROTTLE_CLASSES": ['myutils.throttle.VisitThrottle'],
    "DEFAULT_THROTTLE_RATES": {
        "myscope": '3/m'
    }

}

对当前用户做限流操作

class UserThrottle(SimpleRateThrottle):
    scope = "user_scope"

    def get_cache_key(self, request, view):
        return request.user.username
  • settings配置
# 跟rest_有关的配置
REST_FRAMEWORK = {
    # "DEFAULT_AUTHENTICATION_CLASSES": ["myutils.auth.MyAuthtication"],
    "UNAUTHENTICATED_USER": lambda: "匿名用户哈哈",
    # "DEFAULT_PERMISSION_CLASSES": ["myutils.permission.MyPermission"],
    "DEFAULT_THROTTLE_CLASSES": ['myutils.throttle.VisitThrottle'],
    "DEFAULT_THROTTLE_RATES": {
        "myscope": '3/m',  # 匿名用户一分钟访问3次
        "user_scope": "8/m"  # 登陆用户一分钟访问8次
    }

}
DRF-访问频率配置(节流)
微信截图_20190112163216
上一篇:DRF-基于APIView的认证流程


下一篇:Windows下配置virtualenv和virtualenvwrapper