#!/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])