zoukankan      html  css  js  c++  java
  • 前后端分离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定义好的类,需要用什么就继承什么,且根据继承的类不同,必须要定义该基类里明确规定需要的方法或者属性
    • 限流频率组件必须在认证组件和权限组件验证通过之后才作验证(这是按开发逻辑来的)
    • 全局和局部都还是那一套,不用再多说什么,跟前面的认证组件,权限组件都一个套路
  • 相关阅读:
    每天一道LeetCode--141.Linked List Cycle(链表环问题)
    每天一道LeetCode--119.Pascal's Triangle II(杨辉三角)
    每天一道LeetCode--118. Pascal's Triangle(杨辉三角)
    CF1277D Let's Play the Words?
    CF1281B Azamon Web Services
    CF1197D Yet Another Subarray Problem
    CF1237D Balanced Playlist
    CF1239A Ivan the Fool and the Probability Theory
    CF1223D Sequence Sorting
    CF1228D Complete Tripartite
  • 原文地址:https://www.cnblogs.com/Eeyhan/p/10427351.html
Copyright © 2011-2022 走看看