Django Rest framework 之 节流
- RESTful 规范
- django rest framework 之 认证(一)
- django rest framework 之 权限(二)
- django rest framework 之 节流(三)
- django rest framework 之 版本(四)
- django rest framework 之 解析器(五)
- django rest framework 之 序列化(六)
- django rest framework 之 分页(七)
- django rest framework 之 视图(八)
一、节流
1、简介
节流又叫限流,限制访问。就是通常一个用户在多次请求一个页面,或者点击一个链接的时候,前几次点击是没有问题的,但是一旦连续几次之后,就会出现访问受限,离下一次访问还有50秒等的字样,在django rest framework
中有一个专门的组件来做限制访问。
2、思路
一旦一个用户向资源发送请求,那么根据用户的身份就有两种情况,匿名用户和认证用户。那么根据用户的身份怎么做限制访问?就是要找到用户的唯一标识。
- 匿名用户:对于匿名用户,唯一能用来标识的只有请求的IP。
- 认证用户:认证用户的用户名,或者用户ID等。
用户标识的问题解决了,假设设置的是每分钟只能访问5次,也就是5次/min。当用户发送请求,可以拿到用户的唯一标识,判断用户是第几次访问。有下面几种情况:
- 第一到五次:这是可以通过的,返回资源。
一分钟之内- 第六次:请求被禁止,并返回提示信息。
一分钟之后 - 第六次:请求别允许,返回资源。
- 第六次:请求被禁止,并返回提示信息。
根据上面的情况可以得出以下思路:
当一个用户发送请求的时候,我可以在缓存(django rest framework就是这么做的)中生成一个字典,字典的键值对分别是用户的唯一标识和用户的访问时间,例如下面:
VISIT_RECORD = {
'weilan': [127,125, 121,110,89,68] # 标识第一次访问时间是68秒,第二次访问时间是89秒,第三次访问时间是110秒
}
第一步:当一个用户第一次发送请求的时候,缓存VISIT_RECORD中没有他的键,就会添加一个键是他的表示,值是一个列表,列表中存放他的第一次访问时间为t1。
第二步:当再次发送请求的时候,会先在缓存VISIT_RECORD中找有没有他的键,如果没有,会返回第一步。如果有,取出列表,查看列表中的最后一次访问值T1,并与本次访问时间Tn比较,如果Tn-T1>60s,则将T1删除,如果Tn-T1<60s,则保留T1,因为要保证一分钟之内的访问次数。
第三步:判断当前列表中保存的时间的个数,如果小于5个,说明一分钟之内还没有访问5次,将但访问时间Tn插入到列表头。如果个数超过5个,则说明一分钟已经访问过5次,本次访问已经是第6次,则不插人列表。
这样根据思路就可以写出下面限流类:
import time
VISIT_RECORD = {} # 这里再内存中生成,可以写入缓存
class VisitThrottle(BaseThrottle):
def __init__(self):
self.history = None
def allow_request(self,request,view):
# 1. 获取用户IP 或者认证用户的用户名
remote_addr = self.get_ident(request)
ctime = time.time()
if remote_addr not in VISIT_RECORD: # 判断是否有访问记录
VISIT_RECORD[remote_addr] = [ctime,]
return True
history = VISIT_RECORD.get(remote_addr)
self.history = history
while history and history[-1] < ctime - 60: # 计算出本次访问时间与最远一次访问的时间差
history.pop()
if len(history) < 5:
history.insert(0,ctime)
return True
# return True # 表示可以继续访问
# return False # 表示访问频率太高,被限制
def wait(self):
# 还需要等多少秒才能访问
ctime = time.time()
return 60 - (ctime - self.history[-1])
二、示例
1、目录结构
同样的我们向认证,权限那样再utils包中定义限流组件
2、具体限制访问
对于匿名用户和认证用户做不同的限制访问
from rest_framework.throttling import BaseThrottle,SimpleRateThrottle
class VisitThrottle(SimpleRateThrottle):
scope = "anonymous"
def get_cache_key(self, request, view):
return self.get_ident(request)
class UserThrottle(SimpleRateThrottle):
scope = "user"
def get_cache_key(self, request, view):
return request.user.username
3、配置限流类
可以再setting.py
文件中全局配置,也可以再视图中重写,局部配置,但是访问频率,需要限流类的scope
属性定义。
对于匿名用户,每分钟访问5次,认证用户,每分钟5次
REST_FRAMEWORK = {
"DEFAULT_THROTTLE_CLASSES":["api.utils.throttle.UserThrottle"],
"DEFAULT_THROTTLE_RATES":{
"anonymous":'5/m',
"user":'10/m',
}
}
4、视图
from rest_framework.views import APIView
class UserInfoView(APIView):
authentication_classes = []
permission_classes = []
throttle_classes = [throttle.VisitThrottle] # 标识匿名用户访问
def get(self, request, *args, **kwargs):
print(request.META.get('REMOTE_ADDR')) # 这里可以获取到访问的IP
return HttpResponse('访问成功')
5、请求测试
使用postman或者浏览器发送请求
一分钟连续发送5次,正常
发送第6次时,访问受限
三、源码分析
像django rest framework
之 认证一样进入,request的请求流程,进入源码查看具体权限的操作
1、进入dispath()方法
2、进入initial()方法
3、进入check_throttles()方法
4、获取限流类
获取限流类之后并实例化成对象,使得可以调用具体的方法
同样的默认的是通过全局配置
5、原生的限流类
在rest framework
中也有相应的限流类,主要使用SimpleRateThrottle
,因为在SimpleRateThrottle
中的一些方法已经是实现了我们需要的逻辑
来看一下SimpleRateThrottle具体做了什么
class SimpleRateThrottle(BaseThrottle):
cache = default_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()
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): # scope属性需要在节流类和配置文件中定义,才能达到节流的效果
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): # 这与上面节流的操作相似,是具体的逻辑
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()
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):
self.history.insert(0, self.now)
self.cache.set(self.key, self.history, self.duration)
return True
def throttle_failure(self): # 请求失败的时候
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)
以上就是节流的流程和源码分析
四、总结
节流同样可以通过全局配置和局部配置的方法,影响视图。
值得注意的是,有一个必须要重写的接口get_cache_key()
- 当匿名用户的时候,返回值是匿名用户的IP
- 当为认证用户的时候,可以是用户的任何唯一标识。
因为在VISIT_RECORD
中的键是唯一的。
scope
定义了具体一个节流类怎么节流,在setting.py
文件和节流类中都需要定义。SimpleRateThrottle
中的parse_rate()
方法对scope
进行了解析
- "user":'1/s', 表示一秒访问一次
- "user":'1/m', 表示一分钟访问一次
- "user":'1/h', 表示一小时访问一次
- "user":'1/d', 表示一天访问一次
Django Rest framework 之 节流的更多相关文章
- Django Rest framework 之 序列化
RESTful 规范 django rest framework 之 认证(一) django rest framework 之 权限(二) django rest framework 之 节流(三) ...
- Django Rest framework 之 解析器
RESTful 规范 django rest framework 之 认证(一) django rest framework 之 权限(二) django rest framework 之 节流(三) ...
- Django Rest framework 之 版本
RESTful 规范 django rest framework 之 认证(一) django rest framework 之 权限(二) django rest framework 之 节流(三) ...
- Django Rest framework 之 权限
django rest framework 之 认证(一) django rest framework 之 权限(二) django rest framework 之 节流(三) django res ...
- Django Rest framework 之 认证
django rest framework 官网 django rest framework 之 认证(一) django rest framework 之 权限(二) django rest fra ...
- Django Rest framework 之 视图
RESTful 规范 django rest framework 之 认证(一) django rest framework 之 权限(二) django rest framework 之 节流(三) ...
- Django Rest framework 之 分页
RESTful 规范 django rest framework 之 认证(一) django rest framework 之 权限(二) django rest framework 之 节流(三) ...
- Django rest framework源码分析(3)----节流
目录 Django rest framework(1)----认证 Django rest framework(2)----权限 Django rest framework(3)----节流 Djan ...
- Django rest framework(3)----节流
目录 Django组件库之(一) APIView源码 Django restframework (1) ----认证 Django rest framework(2)----权限 Django res ...
随机推荐
- 【BZOJ】 Hash Killer I II III
前言 这里只是一个整理... Solution Hash Killer I Hash Killer II
- 开源播放器 ijkplayer (一) :使用Ijkplayer播放直播视频
1.ijkplayer 编码 IjkPlayer支持硬解码和软解码. 软解码时不会旋转视频角度这时需要你通过onInfo的what == IMediaPlayer.MEDIA_INFO_VIDEO_R ...
- bootstrap教程,SQL
版权声明:未经博主允许不得转载 SQL DDL数据定义语言 TPL事务处理语言 DCL数据控制语言 DML数据操作语言 DML SELECT INSERT UPDATE DELETE Join从句 J ...
- C#6.0语言规范(二) 词法结构
程式 AC#程序由一个或多个源文件组成,正式称为编译单元(编译单元).源文件是Unicode字符的有序序列.源文件通常与文件系统中的文件一一对应,但不需要此对应关系.为了获得最大的可移植性,建议使用U ...
- I2C软件调试思路并知识总结
I2C是一种只使用两根线的串行通信协议.一根线是串行数据线SDA,另外一种是串行时钟线SCL. I²C允许相当大的工作电压范围,但典型的电压准位为+3.3V或+5v. I²C的参考设计使用一个7比特长 ...
- python ---解决高并发超卖问题
使用redis 解决美多商城超卖的问题 import redis r = redis.Redis(host='localhost', port=6379) #定义过载 def limit_handle ...
- Servlet-生命周期简介
Servlet生命周期可分为5个步骤 加载Servlet.当Tomcat第一次访问Servlet的时候,Tomcat会负责创建Servlet的实例 初始化.当Servlet被实例化后,Tomcat会调 ...
- python语法基础-初始化/继承
写了一些程序,基本上都是直接def函数 然后在main方法中 调用 但是在一些应用程序中 会有基本语法的使用(初始化,继承) 初始化: 1.在程序执行时一定执行一次的操作 2.python中初始化in ...
- python 打包exe
下载及安装:pip install pyinstaller 执行命令: pyinstaller -F xxx.py pyinstaller --onefile meng.py 可以运行的exe文件位于 ...
- AcceptEx与完成端口(IOCP)结合实例
前言 在windows平台下实现高性能网络服务器,iocp(完成端口)是唯一选择.编写网络服务器面临的问题有:1 快速接收客户端的连接.2 快速收发数据.3 快速处理数据.本文主要解决第一个问题. A ...