zoukankan      html  css  js  c++  java
  • restframework之节流

    基本思路(原生Django而言):

      在django2.x中,若出现节流(访问频率控制)的需求,我们首先想到的是使用一个字典(dict类型)来存储所有IP地址的访问时间记录,这是针对于匿名用户(IP)而言的

    {
        "111.222.3.44": [1000, 900, 700, 500, 10....],
        "1.333.44.555": [1200, 900, 20, 10.....]              
    }

      原生request的消息体中,在environ下的REMOTE_ADDR保存了客户端的IP地址

      

      由于请求经过WSGIRequest封装后,必经中间件层,所以考虑通过中间件来实现节流功能

    from django.utils.deprecation import MiddlewareMixin
    from django.http.response import HttpResponse
    import time
    
    MAX_PER_VISITED_NUMS = 3
    VISITED_IP_THROTTLE = dict()
    
    class ThrottleMiddleware(MiddlewareMixin):
        """
        节流中间件
        VISITED_IP_THROTTLE每分钟最大访问次数
        """
        def request_allowed(self, request):
            """自定义访问频率限制器, 用于限制匿名用户的访问频率限制"""
            ip = request.META['REMOTE_ADDR']
            cur_time = time.time()
            # 如果ip在限制器中有记录
            if ip in VISITED_IP_THROTTLE:
                visiting_record = VISITED_IP_THROTTLE[ip]
    
                while visiting_record:
                    # 与列表中最后一次访问记录的时间差大于60秒, 移除最后一次记录并继续循环
                    if cur_time - 60 >= visiting_record[-1]:
                        visiting_record.pop(-1)
                        continue
                    # 访问记录列表超过最大访问次数
                    if len(visiting_record) >= MAX_PER_VISITED_NUMS:
                        return False
                    # 与列表中最后一次访问记录的时间差小于60秒
                    visiting_record.insert(0, cur_time)
                    return True
    
            # 无记录则新建该IP访问记录
            VISITED_IP_THROTTLE[ip] = list()
            VISITED_IP_THROTTLE[ip].insert(0, cur_time)
            return True
    
        def process_request(self, request):
            if self.request_allowed(request):
                print(True)
                return HttpResponse("True")
            else:
                print(False)
                return HttpResponse("False")

      运行结果:

      

      这是针对在访问用户较少的情况下才采用的全局变量来存储访问记录, 实际情况中,最好使用redis作为缓存来存储记录。

    restframework版:

      自定义节流控制器

      使用redis缓存访问记录(hash类型)

      redispool.py(作连接池, 参数设置为你自己的redis连接信息)

    import redis
    from vue_shop import settings
    
    REDIS_POOL = redis.ConnectionPool(**settings.REDIS_KWARGS)

      throttle.py

    import time
    import redis
    from utils.redispool import REDIS_POOL
    import json
    from rest_framework.throttling import SimpleRateThrottle
    
    class AnonymityUserThrottle(object):
        """
        自定义匿名用户节流器, 采用redis缓存访问记录
        MAX_PER_VISITED_NUMS: 每分钟最高访问次数
        name: 缓存(redis)中,hash类型的name
        """
        MAX_PER_VISITED_NUMS = 3
        name = "AnonymityVisitedRecord"
    
        def allow_request(self, request, view):
            """
            进行是否可访问的逻辑判断
            :param request: drf's request
            :param view:
            :return: bool
            """
            IP_ADDR = request.META.get("REMOTE_ADDR", None)
            cur_visit_time = time.time()
            redis_conn = redis.Redis(connection_pool=REDIS_POOL)
            ips_record = redis_conn.hget(self.name, IP_ADDR)
            print(ips_record)
            if ips_record:
                history_visit_list = json.loads(ips_record.decode())
                while history_visit_list:
                    # [120, 99, 40]
                    # 最远一次访问时间B与当前时间A的时间差大于60秒,则删除B,如此循环
                    if cur_visit_time - history_visit_list[-1] >= 60:
                        history_visit_list.pop(-1)
                        redis_conn.hset(self.name, IP_ADDR, json.dumps(history_visit_list))
                        continue
                    if len(history_visit_list) > self.MAX_PER_VISITED_NUMS:
                        return False
                    history_visit_list.insert(0, cur_visit_time)
                    redis_conn.hset(self.name, IP_ADDR, json.dumps(history_visit_list))
                    return True
    
            new_ip_record = list()
            new_ip_record.insert(0, cur_visit_time)
            redis_conn.hset(self.name, IP_ADDR, json.dumps(new_ip_record))
            return True
    
        def wait(self):
            """
            Optionally, return a recommended number of seconds to wait before
            the next request.
            """
            return None

      运行结果:

      

      内置的节流控制器

    class SimpleAnonymityUsertThrottle(SimpleRateThrottle):
        """
        使用restframework内置的节流类,针对于的匿名用户的访问控制
        """
        scope = "Anonymity"
    
        def get_cache_key(self, request, view):
            """
            返回用户的唯一标识
            """
            # return request.META.get("REMOTE_ADDR")
            return self.get_ident(request)
    
    
    class CertifiedUserThrottle(SimpleRateThrottle):
        """
        对认证通过的用户进行节流控制
        """
        scope = "CertifiedUser"
    
        def get_cache_key(self, request, view):
            """返回唯一用户标识"""
            return request.user.username

       scope参数依赖配置:

    REST_FRAMEWORK = 
    {
        'DEFAULT_THROTTLE_RATES': {
            'Anonymity': '3/m',
            'realUser': '6/m',
        },
    }

      

  • 相关阅读:
    jquery的优势
    基于指纹识别技术的超市储物箱设计
    jquery核心
    jquery中的筛选
    红包算法设计
    jquery中trim() 去掉收尾空格
    jquery中效果的创建
    项目缓存
    StringUtils方法全集
    IE8下onclick事件不支持
  • 原文地址:https://www.cnblogs.com/kisun168/p/11352998.html
Copyright © 2011-2022 走看看