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 ...
随机推荐
- java Atomic compareAndSet部分原理分析
以AtomicLong的compareAndSet方法举例.先说结论:如果CPU支持,则基于CPU指令(CMPXCHG8)实现:否则使用ObjectLocker锁实现. 分析过程如下: 该方法在jdk ...
- 201871010126 王亚涛 《面向对象程序设计(java)》 第二周学习总结
项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...
- linux 指定用户 启动 程序
sudo -H -u {username} /bin/bash -c "python test.py &" "&" 后台运行指令 本人亲测可用 ...
- blocking cache和non-blocking cache
- a Blocking Cache will not accept any more request until the miss is taken care of. - a Non-blockin ...
- matlab-层次分析法
层次分析法(AHP)是把问题条理化.层次化,构造出一个有层次的结构模型的方法. 比如要选择旅游地,有3个选择方案,苏杭.北戴河和桂林.选择过程需要考虑多个因素,比如景色.费用.居住.饮食和旅途. 1. ...
- Qt常用类——QWidget
QWidget类是所有用户界面对象的基类. Widget是用户界面的基本单元:它从窗口系统接收鼠标,键盘和其他事件,并在屏幕上绘制自己. 每个Widget都是矩形的,它们按照Z-order进行排序.
- LOJ2778 [BOI2018]基因工程 随机化
题面 不想写了...留坑吧... 基本思想可参照随机化解决判同问题的总结 代码: #include<bits/stdc++.h> using namespace std; #define ...
- mac 下使用nasm
#安装nasm brew install nasm #创建文件 vi hello.asm 写入如下内容 msg: db "hello world!", 0x0a len: equ ...
- Android Studio 之 ROM【3】,LiveData+ViewModel+AsyncTask+Repository+RecyclerView
教程地址:https://www.bilibili.com/video/av65180549 源码地址:https://github.com/longway777/Android-2019-Tutor ...
- ping-pong buffer
1 什么是pingpong? pingpong是一种数据缓存的手段,通过pingpong操作可以提高数据传输的效率. 2 什么时候需要pingpong? 在两个模块间交换数据时,上一级处理的结果不能马 ...