Django:RestFramework之-------频率控制
5.频率控制
5.1频率监控代码实现
import time
VISIT_RECORD = {}
class VisitThrottle(object):
def __init__(self):
#定义历史记录,生产环境上,应该将其保存在redis
self.history = []
def allow_request(self,request,view):
#1.获取用户IP
remote_addr = request._request.META.get("REMOTE_ADDR")
print(remote_addr)
#记录访问时的时间
ctime = time.time()
#判断当前IP是否在访问记录中
if remote_addr not in VISIT_RECORD:
VISIT_RECORD[remote_addr] = [ctime,]
return True
#拿取当前访问IP记录
history = VISIT_RECORD.get(remote_addr)
#将历史访问时间记录,复制给self.history,以方便wait方法调用,通过wait方法告诉用户一些信息
self.history = history
#逻辑判断只记录1分钟内访问记录。
while history and history[-1] < ctime-60:
history.pop()
#访问历史列表中时间记录不能大于3
if len(history) < 3:
history.insert(0,ctime)
return True
def wait(self):
"""用于提示多少秒后才可以重新访问"""
#记录当前时间
ctime = time.time()
#返回告知用户还有多长时间可以再次访问
return 60-(ctime - self.history[-1])
class AuthView(APIView):
#用于频率限制
throttle_classes = [VisitThrottle,]
def post(self,request,*args,**kwargs):
ret = {"code":1000,"msg":None}
return JsonResponse(ret)
效果:
当发送请求在监测频率范围内:
当发送请求超出监测频率范围:返回信息提示,此信息提示为wait定义的。
5.2频率表权限源码解析
def dispatch(self, request, *args, **kwargs):
...
try:
#执行initial方法
self.initial(request, *args, **kwargs)
...
#---------------------------------------------------------
def initial(self, request, *args, **kwargs):
...
self.check_throttles(request)#用于限制频率
...
#---------------------------------------------------------
def check_throttles(self, request):
throttle_durations = []
#遍历 循环get_throttles
for throttle in self.get_throttles():
#如果allow_request返回False,则拒绝访问,并执行wait方法,抛出提示用户信息
if not throttle.allow_request(request, self):
throttle_durations.append(throttle.wait())
if throttle_durations:
self.throttled(request, max(throttle_durations))
#---------------------------------------------------------
def get_throttles(self):
#实例化返回一个列表,当用户定义throttle_classes,则返回用户定义的[对象,对象...]
#如果用户没有定义,将使用django内置配置:throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES
return [throttle() for throttle in self.throttle_classes]
5.3全局和局部配置权限:
#全局配置settings.py
REST_FRAMEWORK={
'DEFAULT_THROTTLE_CLASSES':['app.utils.throttle.VisitThrottle']
}
#局部配置
类下面定义throttle_classes =[频率监测类,]
5.4内置频率类
class BaseThrottle:
def allow_request(self, request, view):
"""
如果应该允许请求,则返回True,否则返回False。
"""
raise NotImplementedError('.allow_request() must be overridden')
def get_ident(self, request):
"""
通过解析HTTP_X_FORWARDED_FOR(如果存在且代理数> 0)来识别发出请求的机器。如果不可用,则使用所有HTTP_X_FORWARDED_FOR(如果可用),如果不使用,则不使用REMOTE_ADDR
"""
xff = request.META.get('HTTP_X_FORWARDED_FOR')
remote_addr = request.META.get('REMOTE_ADDR')
num_proxies = api_settings.NUM_PROXIES
if num_proxies is not None:
if num_proxies == 0 or xff is None:
return remote_addr
addrs = xff.split(',')
client_addr = addrs[-min(num_proxies, len(addrs))]
return client_addr.strip()
return ''.join(xff.split()) if xff else remote_addr
def wait(self):
"""
(可选)返回建议的秒数,以等待下一个请求
"""
return None
#BaseThrottle定义了get_ident用于获取访问用户ID,这样可以自定义频率监测类继承BaseThrottle,通过调用父类方法,获取访问用户ID
remote_addr = self.get_ident(request)
#------------------------------------------------------------------------------------------------
class SimpleRateThrottle(BaseThrottle):
"""一个简单的缓存实现,只需要覆盖.get_cache_key()即可。速率(请求/秒)由View类的“ rate”属性设置。该属性是形式为'number_of_requests / period'的字符串。周期应为以下之一:('s','sec','m','min','h','hour','d','day')用于限制的先前请求信息存储在缓存中"""
cache = default_cache
timer = time.time
cache_format = 'throttle_%(scope)s_%(ident)s'
scope = None
THROTTLE_RATES = api_settings.DEFAULT_THROTTLE_RATES
def __init__(self):
if not getattr(self, 'rate', None):
self.rate = self.get_rate()
#num_requests表示次数,duration表示秒/分数
self.num_requests, self.duration = self.parse_rate(self.rate)
def get_cache_key(self, request, view):
"""
应该返回一个唯一的可用于节流的缓存键。必须重写。如果不应该限制请求,则可能会返回“无”
"""
raise NotImplementedError('.get_cache_key() must be overridden')
def get_rate(self):
"""
确定允许请求速率
"""
if not getattr(self, 'scope', None):
msg = ("You must set either `.scope` or `.rate` for '%s' throttle" %
self.__class__.__name__)
raise ImproperlyConfigured(msg)
try:
return self.THROTTLE_RATES[self.scope]
except KeyError:
msg = "No default throttle rate set for '%s' scope" % self.scope
raise ImproperlyConfigured(msg)
def parse_rate(self, rate):
"""
给定请求速率字符串
"""
if rate is None:
return (None, None)
num, period = rate.split('/')
num_requests = int(num)
duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]
return (num_requests, duration)
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
#从缓存拿历史记录, cache = default_cache为Django内置缓存
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()
def throttle_success(self):
#成功返回
"""
Inserts the current request's timestamp along with the key
into the cache.
"""
self.history.insert(0, self.now)
self.cache.set(self.key, self.history, self.duration)
return True
def throttle_failure(self):
#失败返回
"""
Called when a request to the API has failed due to throttling.
"""
return False
def wait(self):
"""
返回建议的下一个请求时间(以秒为单位)。
"""
if self.history:
remaining_duration = self.duration - (self.now - self.history[-1])
else:
remaining_duration = self.duration
available_requests = self.num_requests - len(self.history) + 1
if available_requests <= 0:
return None
return remaining_duration / float(available_requests)
#SimpleRateThrottle 内置分装好了监测频率各种(成功返回,错误返回,定义访问频次,返回下一次请求时间,确定速率等)方法。这样我们自己定义类继承SimpleRateThrottle
#更改自定义频率监测:
class VisitThrottle(SimpleRateThrottle):
scope = "key"#根据scope的值,去配置文件找频率设置
def get_cache_key(self, request, view):
return self.get_ident(request)
#settings.py配置
REST_FRAMEWORK={
'DEFAULT_THROTTLE_CLASSES':['app.utils.throttle.VisitThrottle'],
"DEFAULT_THROTTLE_RATES":{
#设置频率3/m表示每分钟最多访问3次,并给予标识
'key':'3/m'
}
}
5.5对当前登录用户进行操作
#settings.py配置
REST_FRAMEWORK={
'DEFAULT_THROTTLE_CLASSES':['app.utils.throttle.VisitThrottle'],
"DEFAULT_THROTTLE_RATES":{
'key':'3/m',
#用于登录用户频率监测配置设置
'vipkey':'10/m',
}
}
#throttle.py
#定义登录用户频次监测类
class UserThrottle(SimpleRateThrottle):
scope = "vipkey"
def get_cache_key(self, request, view):
#返回登录用户名
return request.user.username
#因定义登录用户检测的类,不能放入settings配置,应予以局部添加
class OrderView(APIView):
throttle_classes = [UserThrottle, ]
5.6小总结:
基本使用:
类 继承:BaseThrottle 实现:allow_request,wait 方法
类 继承:SimpleRateThrottle 实现:get_cache_key ,scope (配置文件中的key,去找频率设置)
Django:RestFramework之-------频率控制的更多相关文章
- rest-framework之频率控制
rest-framework之频率控制 本文目录 一 频率简介 二 自定义频率类,自定义频率规则 三 内置频率类及局部使用 四 内置频率类及全局使用 五 源码分析 回到目录 一 频率简介 为了控制用户 ...
- django restframework serializer 增加自定义字段
在使用django restframework serializer 序列化在django中定义的model时,有时候我们需要额外在serializer中增加一些model中没有的字段.有两种方法实现 ...
- django restframework
一.django restframework 请求流程源码剖析 上面的认证一个流程是rest_framework的关于APIauth的认证流程,,这个流程试用权限.频率.版本.认证.这个四个组件都是通 ...
- django restframework jwt
既然要来学习jwt(json web token),那么我们肯定是先要了解jwt的优势以及应用场景--跨域认证. $ pip install djangorestframework-jwt 传统coo ...
- django restframework 快速入门
django restframework 快速入门 基本流程 建立 Models 依靠 Serialiers 将数据库取出的数据 Parse 为 API 的数据(可用于返回给客户端,也可用于浏览器显示 ...
- Django Restframework 实践(一)
具备以下知识: django http://www.cnblogs.com/menkeyi/p/5882464.html http://www.cnblogs.com/menkeyi/p/588245 ...
- django: rest-framework的 分页和过滤
django: rest-framework的 分页和过滤 2018年06月28日 10:09:01 weixin_42359464 阅读数:136 标签: flaskrestframeworkdja ...
- django restframework 的日常使用
本文讨论 django restframework 的日常使用,满足常用 api 编写的需求,比如 List, Detail, Update, Put, Patch 等等.探讨 django rest ...
- Django RestFramework (DRF)
准备: 下载 pip install djangorestframework 一 APIView源码解析 1 预备知识 CBV(class based view)FBV(function based ...
随机推荐
- MapReduce 简单开发
先给出 maven 依赖配置 <properties> <hadoop.version>2.6.0</hadoop.version> </properties ...
- SpringBoot——IDEA使用 Spring Initializer快速创建项目【四】
前言 使用Spring Initializer快速创建项目 步骤 首先肯定是打开我们的IDEA的编辑器呀~ 创建项目 File -> New -> Project Spring Initi ...
- vue之非父子通信
一.非父子通信: 思路: 找个中间存储器,组件一把信息放入其中,组件二去拿 代码如下: let hanfei = new Vue(); # 实列化个空的vue对象,作为中间存储器来时间 ...
- Linux进程通信的几种方式总结
进程通信的目的 数据传输 一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M字节之间 共享数据 多个进程想要操作共享数据,一个进程对共享数据 通知事 一个进程需要向另一个或一组进程发 ...
- 网络协议 19 - RPC协议综述
这几年微服务很火,想必各位博友或多或少的都接触过.微服务概念中, 各服务间的相互调用是不可或缺的一环.你知道微服务之间是通过什么方式相互调用的吗? 你可能说,这还不简单,用 socket 呗. ...
- luogu p2622关灯问题II
luogu p2622关灯问题II 题目描述 现有n盏灯,以及m个按钮.每个按钮可以同时控制这n盏灯--按下了第i个按钮,对于所有的灯都有一个效果.按下i按钮对于第j盏灯,是下面3中效果之一:如果a[ ...
- helm repository 相关
chart repo是一个可用来存储index.yaml与打包的chart文件的HTTP server.当要分享chart时,需要上传chart文件到chart仓库,任何一个能够提供yaml与tar文 ...
- windows,office激活工具推荐
微软的操作系统windows,办公软件office,都需要付费.今天,蒟蒻菌带来一部软件,可以激活上述软件,那就是: heu_kms_activator_v19.5.1 二话不说,立即使用: 可以根据 ...
- Jmeter之Bean shell使用(二)(转载)
转载地址:https://www.cnblogs.com/puresoul/p/4949889.html 上一篇Jmeter之Bean shell使用(一)简单介绍了下Jmeter中的Bean she ...
- Windows忘记BIOS密码/操作系统密码处理办法汇总
一.说明 关于电脑,在大学之前是知之甚少的.举几个例子,一是刚上大学时我还是分不清主机和显示器哪个才是电脑:二是应该是大一上学期陪窒友Z到电科买电脑,我问导购员XP和Win7什么关系----我一直怀疑 ...