访问频率控制(节流)
class VisitThrottle(object):
def allow_request(self, request, view):
return True # False表示访问频率太高被限制
def wait(self):
return None
class VisitThrottle(object):
def allow_request(self, request, view):
# 1. 获取用户ip
remote_addr = request._request.META.get("REMOTE_ADDR")
#print(remote_addr)
...
import time
# 存放访问记录(一般放数据库或者缓存中)
VISIT_RECORD = {}
class VisitThrottle(object):
def allow_request(self, request, view):
# 1. 获取用户ip
remote_addr = request._request.META.get("REMOTE_ADDR")
# print(remote_addr)
# 2. 添加到访问记录中
ctime = time.time()
if remote_addr not in VISIT_RECORD:
VISIT_RECORD[remote_addr] = [ctime, ]
return True
return False # False表示访问频率太高被限制
def wait(self):
return None
- 两种情况,之前说的是第一种,当用户没有访问的时候的情况,记录用户的访问记录的列表里面没有用户访问,但是如果用户已经访问,而我们需求是1分钟内只能访问3次,我们需要改进代码
class VisitThrottle(object):
def allow_request(self, request, view):
# 1. 获取用户ip
remote_addr = request._request.META.get("REMOTE_ADDR")
# print(remote_addr)
# 2. 添加到访问记录中
ctime = time.time()
# 当VISIT_RECORD中没有这个记录,可以直接访问,添加一个记录
if remote_addr not in VISIT_RECORD:
VISIT_RECORD[remote_addr] = [ctime, ]
return True
history = VISIT_RECORD.get(remote_addr)
# 拿到最后历史记录里面的最后一个时间,如果最后一个时间小于当前时间-60
while history and history[-1] < ctime - 60:
history.pop()
if len(history) < 3:
history.insert(0,ctime)
return True
return False # False表示访问频率太高被限制
def wait(self):
return None
- wait返回的值是一个提示,表示多少秒以后可以访问
def wait(self):
return 10 # 写死了10秒
def wait(self):
"""
还需要等多少秒可以访问
:return:
"""
ctime = time.time()
return 60 - (ctime - self.history[-1])
源码流程
内置控制频率的类
from rest_framework.throttling import BaseThrottle
class VisitThrottle(BaseThrottle):
def __init__(self):
self.history = None
def allow_request(self, request, view):
# 1. 获取用户ip
remote_addr = request._request.META.get("REMOTE_ADDR")
# print(remote_addr)
# 2. 添加到访问记录中
ctime = time.time()
# 当VISIT_RECORD中没有这个记录,可以直接访问,添加一个记录
if remote_addr not in VISIT_RECORD:
VISIT_RECORD[remote_addr] = [ctime, ]
return True
history = VISIT_RECORD.get(remote_addr)
self.history = history
# 拿到最后历史记录里面的最后一个时间,如果最后一个时间小于当前时间-60
while history and history[-1] < ctime - 60:
history.pop()
if len(history) < 3:
history.insert(0, ctime)
return True
return False # False表示访问频率太高被限制
def wait(self):
"""
还需要等多少秒可以访问
:return:
"""
ctime = time.time()
return 60 - (ctime - self.history[-1])
# 跟rest_有关的配置
REST_FRAMEWORK = {
# "DEFAULT_AUTHENTICATION_CLASSES": ["myutils.auth.MyAuthtication"],
"UNAUTHENTICATED_USER": lambda: "匿名用户哈哈",
# "DEFAULT_PERMISSION_CLASSES": ["myutils.permission.MyPermission"],
"DEFAULT_THROTTLE_RATES": {
"myscope": '3/m'
}
}
def __init__(self):
# 在构造方法里面,通过反射调用rate
if not getattr(self, 'rate', None):
# "3/m"
self.rate = self.get_rate()
# 3次 self.num_requests 60秒 self.duration
self.num_requests, self.duration = self.parse_rate(self.rate)
class VisitThrottle(SimpleRateThrottle):
scope = "myscope"
def get_cache_key(self, request, view):
return self.get_ident(request)
def allow_request(self, request, view):
"""
Implement the check to see if the request should be throttled.
On success calls `throttle_success`.
On failure calls `throttle_failure`.
"""
if self.rate is None:
return True
# 方法缓存里面
self.key = self.get_cache_key(request, view)
if self.key is None:
return True
# 去缓存里面拿到所有记录
self.history = self.cache.get(self.key, [])
# 获取当前时间
self.now = self.timer()
# Drop any requests from the history which have now passed the
# throttle duration
while self.history and self.history[-1] <= self.now - self.duration:
self.history.pop()
if len(self.history) >= self.num_requests:
# 失败
return self.throttle_failure()
# 成功
return self.throttle_success()
# 跟rest_有关的配置
REST_FRAMEWORK = {
# "DEFAULT_AUTHENTICATION_CLASSES": ["myutils.auth.MyAuthtication"],
"UNAUTHENTICATED_USER": lambda: "匿名用户哈哈",
# "DEFAULT_PERMISSION_CLASSES": ["myutils.permission.MyPermission"],
"DEFAULT_THROTTLE_CLASSES": ['myutils.throttle.VisitThrottle'],
"DEFAULT_THROTTLE_RATES": {
"myscope": '3/m'
}
}
对当前用户做限流操作
class UserThrottle(SimpleRateThrottle):
scope = "user_scope"
def get_cache_key(self, request, view):
return request.user.username
# 跟rest_有关的配置
REST_FRAMEWORK = {
# "DEFAULT_AUTHENTICATION_CLASSES": ["myutils.auth.MyAuthtication"],
"UNAUTHENTICATED_USER": lambda: "匿名用户哈哈",
# "DEFAULT_PERMISSION_CLASSES": ["myutils.permission.MyPermission"],
"DEFAULT_THROTTLE_CLASSES": ['myutils.throttle.VisitThrottle'],
"DEFAULT_THROTTLE_RATES": {
"myscope": '3/m', # 匿名用户一分钟访问3次
"user_scope": "8/m" # 登陆用户一分钟访问8次
}
}