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 ...
随机推荐
- 201871010126 王亚涛 《面向对象程序设计(java)》 第二周学习总结
项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...
- 常见bug类别
- HS编码查询hs海关编码列表
HS编码查询是外面人一个必须技能,以下是ytkah整理的hs海关编码列表,罗列了几乎所有的hs商品编码,方便大家查询,也欢迎大家转给有需要的朋友! 编号 名称 01022100 荷斯坦青年牛 0103 ...
- 如何用<dl>标签做表格而不用table标签
我们都知道很多的内容编辑器(TinyMCE编辑器.fck)都有插入表格功能,快速方便,但是这些表格用到的<table>标签,可以查看html源代码就能发现,table标签对搜索引擎不是很友 ...
- JS常用关键字总结
in: 案例1.遍历对象: for(key in obj) { console.info( key+":"+obj[key]; ) }; 案例2.判断对象中是否有属性: " ...
- 微信小程序自动化jest模拟场景/切出/切入
await miniProgram.evaluate(() => getApp().clickBanner({ path: "pages/game/home/home", q ...
- Hibernate框架学习3
一对多|多对一 一对多 多对一 级联操作 结论: 简化操作.一定要用,save-update,不建议使用delete. 关系维护 在保存时.两方都会维护外键关系.关系维护两次,冗余了. 多余的维护关系 ...
- EXCEPTION_HIJACK(0xe0434f4e)异常的抛出过程
样例工程 在VS2013里新建一个C#控制台工程,写下如下代码: using System; using System.Collections.Generic; using System.Linq; ...
- 洛谷 P1801 黑匣子_NOI导刊2010提高(06) 题解
昨晚恶补了一下二叉堆的内容 然后就找了几个二叉堆的题来做awa 然后发现用二叉堆做这题复杂度是O(nlogn) 但是有O(n)的解法 (某大佬这么说) 思路大概就是: 利用一个大根堆一个小根堆来维护第 ...
- 【louguP2234】[HNOI2002]营业额统计(链表)
题目链接 离线用链表维护,先按权值排序,建立链表,记录每一天在链表的位置,然后按天数从大到小查询,查询完删除 #include<algorithm> #include<iostrea ...