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

简介: 访问频率控制(节流)我们可以先编写一个类class VisitThrottle(object): def allow_request(self, request, view): return True # False表...

访问频率控制(节流)

  • 我们可以先编写一个类
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
目录
相关文章
|
前端开发 数据可视化 大数据
Echarts通过ajax获取数据定时更新轮询的解决方案及问题分析
Echarts通过ajax获取数据定时更新轮询的解决方案及问题分析
255 0
|
23天前
|
存储 JavaScript 中间件
在 Redux 动态路由中进行数据预加载时,如何处理数据加载失败的情况?
【10月更文挑战第22天】在 Redux 动态路由中进行数据预加载时,数据加载失败是需要妥善处理的情况
29 4
|
2月前
axios全局做节流,解决多次点击导致多次请求接口
本文介绍了如何在Axios请求中实现全局节流,以防止用户快速多次点击导致重复发送相同请求的问题。
75 2
|
2月前
|
前端开发 JavaScript UED
debounce(防抖)和 throttle(节流)是两种非常实用的技术,它们可以帮助我们有效地控制函数的执行频率,提高应用的性能和用户体验。
【9月更文挑战第1天】在前端开发中,频繁的用户操作可能导致性能问题。为此,debounce(防抖)和 throttle(节流)技术应运而生,有效控制函数执行频率,提升应用性能和用户体验。debounce 原理是在一定时间内仅执行最后一次事件,减少不必要的计算;throttle 则确保函数按固定频率执行,保证基本响应速度。二者广泛应用于搜索实时反馈、滚动事件处理等场景,可通过原生 JavaScript 或第三方库如 Lodash 实现。正确使用可显著改善应用性能。
52 8
|
2月前
|
NoSQL 算法 Java
接口限流是一种控制访问频率的技术
在高并发场景下,合理的接口限流、防重复提交及接口防抖机制对保障系统稳定性至关重要。本文介绍了如何利用AOP在不改变业务代码的前提下,灵活添加这些功能。具体包括:通过`@AccessLimit`注解实现接口限流,利用Redis进行计数与控制;通过`@RepeatSubmit`注解防止重复提交,确保数据一致性;通过`@AntiShake`注解实现接口防抖,提升用户体验。此外,提供了基于Redisson和Spring Cloud的实现示例。
45 4
|
3月前
|
JavaScript 前端开发 API
【Azure 应用服务】Azure Function HTTP 触发后, 230秒就超时。而其他方式触发的Function, 执行5分钟后也超时,如何调整超时时间?
【Azure 应用服务】Azure Function HTTP 触发后, 230秒就超时。而其他方式触发的Function, 执行5分钟后也超时,如何调整超时时间?
|
4月前
|
存储 前端开发 安全
前端轮询问题之在setTimeout版轮询中,如何避免旧请求的响应继续触发定时
前端轮询问题之在setTimeout版轮询中,如何避免旧请求的响应继续触发定时
|
4月前
|
JavaScript
vue 数据变化触发页面响应的三种方式(解决:数据变化页面无响应/不刷新的问题)【含原理】
vue 数据变化触发页面响应的三种方式(解决:数据变化页面无响应/不刷新的问题)【含原理】
324 0
|
4月前
vue3 在 watchEffect 里中断未完成的 axios 请求(只保留最后一次请求的方法---连续点击查询按钮的优化)
vue3 在 watchEffect 里中断未完成的 axios 请求(只保留最后一次请求的方法---连续点击查询按钮的优化)
130 0
|
6月前
|
存储 算法 JavaScript
< 今日小技巧:Axios封装,接口请求增加防抖功能 >
今天这篇文章,主要是讲述对axios封装的请求,由于部分请求可能存在延时的情况。使得接口可能存在会被持续点击(即:接口未响应的时间内,被持续请求),导致重复请求的问题,容易降低前后端服务的性能!故提出给axios封装的配置里面,新增一个防抖函数,用来限制全局请求的防抖。
136 0
< 今日小技巧:Axios封装,接口请求增加防抖功能 >