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 ...
随机推荐
- 201871010101-陈来弟《面向对象程序设计(java)》第四周学习总结
...
- 201871010131张兴盼《面向程序设计(java)》第四周学习总结
项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...
- nginx docker 命令: command not found
1. ps: command not found 使用如下命令安装 apt-get update && apt-get -y install procps 2. vim: comman ...
- mysql之字段的修改,添加、删除,多表关系(外键),单表详细操作(增删改)
字段的修改.添加和删除 create table tf1( id int primary key auto_increment, x int, y int ); #修改 alter table tf1 ...
- js如何安全的扩展系统函数
如果直接使用原型扩展系统函数,可能会和其他人的代码相互冲突 为了防止出现冲突,可以使用如下方法进行扩展: function MyArray(){ this.Name="MyArray&quo ...
- Github api【Restful接口规范】
Overview This describes the resources that make up the official GitHub REST API v3. If you have any ...
- 洛谷 U96762 小R与三角形 题解
U96762 小R与三角形 原题链接 题目描述 小 R 所在的小镇有 n 个村落,这 n 个村落分布在一个圆周上,这些村落之间两两有直达的小路,小路可能相交,但不存在三条路交于一点.现在小 R 正好放 ...
- 第02组 Alpha冲刺(1/4)
队名:十一个憨批 组长博客 作业博客 组长黄智 过去两天完成的任务:进行组员分工 GitHub签入记录 接下来的计划:构思游戏实现 还剩下哪些任务:敲代码 燃尽图 遇到的困难:任务分配的不及时,导致很 ...
- 《Linux就该这么学》培训笔记_ch18_使用MariaDB数据库管理系统
<Linux就该这么学>培训笔记_ch18_使用MariaDB数据库管理系统 文章最后会post上书本的笔记照片. 文章主要内容: 初始化MariaDB服务 管理用户以及授权 创建数据库与 ...
- centos上nginx转发tcp请求
下载最新版nginx > wget http://nginx.org/download/nginx-1.17.1.tar.gz 解压缩 > tar zxvf nginx-1.17.1.ta ...