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

访问频率控制(节流)

  • 我们可以先编写一个类
class VisitThrottle(object):
    def allow_request(self, request, view):
        return True  # False表示访问频率太高被限制
    def wait(self):
        return None    
img_7f41070780659b927c02a7bf2429cb85.png
微信截图_20190112111427
  • postman校验
img_dba2f2d4b99d8e4264d1673bb9a35c18.png
微信截图_20190112111522
img_64c8a05c0d0a1b395082e8e5028ca654.png
微信截图_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
img_52b5bfae5276a7e6c96ae90f2f441d07.png
微信截图_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
img_590d7cdbcd4bfd58a8af5c8f219410b6.png
微信截图_20190112113607
  • postman校验
img_f1fc5411de3221ba941da2e6cd62d7c5.png
微信截图_20190112113637
  • wait返回的值是一个提示,表示多少秒以后可以访问
    def wait(self):
        return 10 # 写死了10秒
img_9ea9348c86b0e9d3c4d25b1e173a5d14.png
微信截图_20190112120909
  • 在wait里面拿到访问记录
img_6925193284c7bdfe22e6b806bff8377f.png
微信截图_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])
img_a413669ae810c094d4bfd3cff344c11b.png
微信截图_20190112141225
  • 在SimpleRateThrottle里面
img_de72bfdc3d4c91a253133ed616c8ce4f.png
微信截图_20190112141531
  • get_rate方法
img_40f04ea0d335b64d62b89d68f50c7c71.png
微信截图_20190112141649
  • get_rate方法返回值读取配置文件
img_ee32598c99b4ff1eee9459f971166308.png
微信截图_20190112141713
  • 在我们自己继承的类里面写scpoe
img_263d6697eb0bf4dfb88dfdf5a2b2d1a0.png
微信截图_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'
    }

}
img_e8978b6d7aacf6ab44ca324599bdbe89.png
微信截图_20190112142416
  • 我们设置的频率在源码里面传递
img_318d431d3b49201e12d829677e8b2492.png
微信截图_20190112142521
  • 3/m源码 m表示60
img_09be3d9128bb2565a125fbcbcfa21116.png
微信截图_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方法
img_f6f476654c065dd759e3d37b1dc914b0.png
微信截图_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次
    }

}
img_ed1a67a99d4acc4982a9f54e7a548d20.png
微信截图_20190112163216
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值