• 前后端分离djangorestframework——限流频率组件


    频率限制

    什么是频率限制

    目前我们开发的都是API接口,且是开房的API接口。传给前端来处理的,也就是说,只要有人拿到这个接口,任何人都可以通过这个API接口获取数据,那么像网络爬虫的,请求速度又快,获取的数据又多,不用多久,爬虫方完全可以用我们API的接口来开发一个同样的网站,这样的话,后果就有点严重了,所以我们需要限流,限制访问的频率

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

    频率限制原理

    DRF中的频率控制基本原理是基于访问次数和时间的,自然也可以通过自己定义的方法来实现。当请求进来,走到频率组件的时候,DRF内部会有一个字典来记录访问者的IP,以这个访问者的IP为key,value为一个列表,存放访问者每次访问的时间:

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

    把每次访问最新时间放入列表的最前面,记录这样一个数据结构后,如果我们设置的是10秒内只能访问5次:

    1. 判断访问者的IP是否在这个请求IP的字典里
    2. 保证这个列表里都是最近10秒内的访问的时间,判断当前请求时间和列表里最早的(也就是最后的)请求时间差,如果差大于10秒,说明请求以及不是最近10秒内的,删除掉,继续判断倒数第二个,直到差值小于10秒
    3. 判断列表的长度(即访问次数),是否大于我们设置的5次,如果大于就限流,否则放行,并把时间放入列表的最前面

    局部限流

    和前面的认证组件,权限组件都一个套路了

    url:

    在项目根目录创建一个utils文件夹,在该文件夹下创建一个throttle文件,其内定义一个限流类,allow_request和wait自然也是必须要定义的方法

    view:

    访问:

    再迅速刷新几次,立马出现限流:

    相关代码:

    from rest_framework.views import APIView
    from rest_framework.views import Response
    from utils.auth import MyAuth
    from utils.permisson import MyPermission
    from utils.throttle import MyThrottle
    from DRF.models import User
    import uuid
    
    
    class DemoView(APIView):
        def get(self, request):
            return Response('简单认证')
    
    
    class LoginView(APIView):
        def get(self, request):
            return Response('请登录,如果没有账号请创建')
    
        def post(self, request):
            user = request.data.get('user')
            pwd = request.data.get('pwd')
            token = uuid.uuid4()
            User.objects.create(user=user, pwd=pwd, token=token)
            return Response('创建用户成功')
    
    
    class TestView(APIView):
        authentication_classes = [MyAuth, ]
        permission_classes = [MyPermission, ]
        throttle_classes = [MyThrottle,]
    
        def get(self, request):
            return Response('权限等级测试,VIP用户您好,欢迎访问XX。。。')
    View
    from rest_framework.throttling import SimpleRateThrottle
    import time
    
    
    VISIT_RECORD = {}
    
    
    class MyThrottle(BaseThrottle):
        def __init__(self):
            self.history = None
    
        def allow_request(self, request, view):
            # 以IP作为限流
            # 1.获取请求IP
            ip = request.META.get('REMOTE_ADDR')
            now = time.time()
            # 2.判断是否在访问列表
            if ip not in VISIT_RECORD:
                VISIT_RECORD[ip] = [now, ]
                return True
            history = VISIT_RECORD[ip]
            history.insert(0, now)
            # 3.确保访问列表最多保存不能超过一分钟的
            while history and history[0] - history[-1] > 60:
                history.pop()
            self.history = history
            # 4.如果列表超过允许长度
            if len(history) > 3:
                return False
            else:
                return True
    
        def wait(self):
            # 返回需要等待的时间
            time = 60 - (self.history[0] - self.history[-1])
            return time
    throttle
    from django.urls import path, re_path
    from DRF.views import DemoView, LoginView, TestView
    
    urlpatterns = [
        path(r'', DemoView.as_view()),
        re_path(r'^login/', LoginView.as_view()),
        re_path(r'^test/', TestView.as_view()),
    ]
    url

     全局限流

    也不用多说,自然是在配置文件里配置:

    这样配置重启后就不仅是test视图里有限流了,其他的视图类也会有的

    DRF自带的限流类

     在framework.throttling里,有很多的已经定义好的类

    其他都不变,改下自定义的限流类,这次继承SimpleRateThrottle类:

    配置文件里做如下配置:

    重启访问:

    多次刷新后得,跟我们之前自定义的类一致

    相关代码: 

    from rest_framework.views import APIView
    from rest_framework.views import Response
    from utils.auth import MyAuth
    from utils.permisson import MyPermission
    from utils.throttle import MyThrottle
    from DRF.models import User
    import uuid
    
    
    class DemoView(APIView):
        def get(self, request):
            return Response('简单认证')
    
    
    class LoginView(APIView):
        def get(self, request):
            return Response('请登录,如果没有账号请创建')
    
        def post(self, request):
            user = request.data.get('user')
            pwd = request.data.get('pwd')
            token = uuid.uuid4()
            User.objects.create(user=user, pwd=pwd, token=token)
            return Response('创建用户成功')
    
    
    class TestView(APIView):
        authentication_classes = [MyAuth, ]
        permission_classes = [MyPermission, ]
        throttle_classes = [MyThrottle,]
    
        def get(self, request):
            return Response('权限等级测试,VIP用户您好,欢迎访问XX。。。')
    View
    from rest_framework.throttling import SimpleRateThrottle
    import time
    
    
    
    class MyThrottle(SimpleRateThrottle):
        scope = 'thro' # 限流的配置文件key
    
        def get_cache_key(self, request, view):
            # 如果以IP地址做限流返回IP地址
            return self.get_ident(request)
    throttle
    REST_FRAMEWORK = {
        # "DEFAULT_VERSIONING_CLASS": "utils.version.MyVersion",
        "DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.QueryParameterVersioning",
        "DEFAULT_VERSION": "v1",
        "ALLOWED_VERSIONS": "v1, v2",
        "VERSION_PARAM": "ver",
        # "DEFAULT_AUTHENTICATION_CLASSES": ["utils.auth.MyAuth", ],
        "DEFAULT_THROTTLE_RATES": {
            "WD": "3/m"
        }
    }
    settings

    总结:

    • 自定义限流频率类,必须继承DRF定义好的类,需要用什么就继承什么,且根据继承的类不同,必须要定义该基类里明确规定需要的方法或者属性
    • 限流频率组件必须在认证组件和权限组件验证通过之后才作验证(这是按开发逻辑来的)
    • 全局和局部都还是那一套,不用再多说什么,跟前面的认证组件,权限组件都一个套路
  • 相关阅读:
    《Python 学习手册4th》 第十一章 赋值、表达式和打印
    《Python 学习手册4th》 第十章 Python语句简介
    视图
    表约束
    表值参数
    表操作
    MSSQL数据批量插入优化详细
    SQL Server表分区
    表分区中的分区交换
    maven命令和maven插件
  • 原文地址:https://www.cnblogs.com/Eeyhan/p/10427351.html
Copyright © 2020-2023  润新知