django中限流器使用


#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
__title__ = ''
__author__ = ''
__mtime__ = ''
"""
import logging
import time
from rest_framework.throttling import SimpleRateThrottle

logger = logging.getLogger('mylogger')


class VisitThrottleMixin(object):
    '''
    根据Django-rest-framework的限流原理改写,根据滚动时间分片限流,应对瞬时高并发
    有一定的局限性
    作者:
    '''
    # 60s内可以访问最大次数
    MAX_CAPACITY = 1
    # 设置超时时间
    TIME_DELTA = 60

    def __init__(self):
        # 用于await计算剩余访问时间
        self.history = None
        self.__visit_key = '__visit_throttle_key'

    def allow_request(self, request, view):
        mehtod = request.method
        uri_name = request.path_info
        if mehtod == "POST" and uri_name == "/xxx/xxx/":
            ctime = time.time()
            # 用户第一次访问,将其进行记录,并且返回True,允许继续访问
            if self.__visit_key not in request.session:
                request.session[self.__visit_key] = [ctime, ]
                return True
            # 如果不是第一次访问,获取所有的记录在
            history = request.session.get(self.__visit_key)
            self.history = history
            # 如果有历史访问记录,并且最早一次的访问记录离当前时间超过60s,就删除最早的那个访问记录,
            # 只要为True,就一直循环超过60s就删除最早的一次访问记录
            while history and history[-1] < (ctime - self.TIME_DELTA):
                history.pop()
            # 如果访问记录不超过MAX_CAPACIRY次,就把当前的访问记录插到第一个位置(pop删除最后一个)
            if len(history) < self.MAX_CAPACITY:
                history.insert(0, ctime)
                request.session[self.__visit_key] = history
                return True
            return False
        else:
            return True

    def wait(self):
        '''还需要等多久才能访问'''
        ctime = time.time()
        return self.TIME_DELTA - (ctime - self.history[-1])


VISIT_RECORD = {}  # 定义全局变量,用于存放访问记录


class VisitThrottle(object):
    # 60s内可以访问最大次数
    MAX_CAPACITY = 1
    # 设置超时时间
    TIME_DELTA = 60

    def __init__(self):

        # 用于await计算剩余访问时间
        self.history = None

    def allow_request(self, request, view):
        # 获取用户ip作为唯一的标示
        if request.META.get('HTTP_X_FORWARDED_FOR'):
            remote_addr = request.META.get("HTTP_X_FORWARDED_FOR")
        else:
            remote_addr = request.META.get('REMOTE_ADDR')

        # 获取当前访问的时刻
        ctime = time.time()
        # 这是用户第一次访问,将其进行记录,并且返回True,允许继续访问
        if remote_addr not in VISIT_RECORD:
            VISIT_RECORD[remote_addr] = [ctime, ]
            return True

        # 如果不是第一次访问,获取所有的记录
        history = VISIT_RECORD.get(remote_addr)

        self.history = history
        # 判断最开始的时刻与现在的时刻的差值是否在规定的时间范围内,比如在60s内,如果不在,
        # 可以去除最开始的时刻记录
        while history and history[-1] < ctime - self.TIME_DELTA:
            history.pop()
        # 此时列表中的时刻记录都是在规定的时间范围内,判断时刻的个数也就是访问的次数

        if len(history) < self.MAX_CAPACITY:
            history.insert(0, ctime)
            return True

    def wait(self):
        # 还需要等多少秒才能访问
        ctime = time.time()
        return self.TIME_DELTA - (ctime - self.history[-1])
上一篇:Mysql中类型转换函数Cast()的用法


下一篇:数据的间距问题(重载+函数模板)