Rest Framework之节流(用户访问次数/评率限制)的使用和源码流程
节流(用户访问次数/频率限制)
理解:用户疯狂访问API,占用、消耗大量资源,通过使用节流限制(例如每分钟)的访问频率,有效缓解服务器压力。
节流的方法有很多:基于用户IP限制访问频率、view中限制请求频率、匿名时用IP限制、登录时用Token限制等。
一、节流的基本使用
自定义一个类来做实现节流规则,此类中必须要实现两个方法:allow_request、wait。并推荐继承BaseThrottle。
allow_request中是节流的规则,wait是被限制后需要等待的时间。默认可以不做任何操作
1、url
1 from django.urls import path 2 from api import views 3 4 urlpatterns = [ 5 path('TestView/', views.TestView.as_view()), 6 ]
2、节流规则自定义的类
1 from rest_framework.throttling import BaseThrottle 2 3 4 VISIT_RECORD = {} 5 6 7 class MyThrottles(BaseThrottle): 8 9 def __init__(self): 10 self.history = None 11 12 def allow_request(self, request, view): 13 # 1、获取用户IP 14 # remote_addr = request._request.META.get('REMOTE_ADDR').----->request._request.META.get====request.META.get 15 # remote_addr = self.get_ident(request)父类里面这个方法也是获取IP,可以直接用 16 remote_addr = request.META.get('REMOTE_ADDR') 17 ctime = time.time() 18 if remote_addr not in VISIT_RECORD: 19 VISIT_RECORD[remote_addr] = [ctime, ] 20 # print(remote_addr) 21 return True 22 history = VISIT_RECORD.get(remote_addr) 23 self.history = history 24 while history and history[-1] < ctime - 10: 25 history.pop() 26 if len(history) < 3: 27 history.insert(0, ctime) 28 return True 29 # return True # return False 表示访问频率太高,限制访问 30 31 def wait(self): 32 ''' 33 等待时间显示 34 :return: 35 ''' 36 ctime = time.time() 37 return 60 - (ctime - self.history[-1])
1 class TestView(APIView): 2 3 # throttle_classes = [VisitThrottles, ] 4 5 def get(self, request, *args, **kwargs): 6 # self.dispatch 7 return Response("GET,请求") 8 9 def post(self, request, *args, **kwargs): 10 pass 11 12 def put(self, request, *args, **kwargs): 13 pass 14 15 def delete(self, request, *args, **kwargs): 16 pass
局部视图认证
TestView是后端响应内容,在需要认证的后端响应视图中加上类变量
throttle_classes = [VisitThrottles, ]
加上后,此视图的所有操作均执行这个这个节流规则
全局视图认证(此项目中所有类均自动使用认证规则)
将写认证规则写在一个单独的PY文件中,
配置settings.py,其中“web.utils”是文件的调用路径
1 REST_FRAMEWORK = { 2 "DEFAULT_THROTTLE_CLASSES": ["api.utils.throttle.VisitThrottles"], 3 } 4 }
二、节流的源码流程
1、请求流程第一步,一样是通过进入到dispatch,走到initial中

2、我们从上到下,我们已经都依次看到了,认证、权限。第三个就是咱们的访问频率的限制
3、来看看这个方法里面做了些什么,
3.1、我们看到了循环语句,这里根据以前的经验,get_throttles里面应该是一个列表生成式,将每一个节流规则类的对象生成,并构成列表
列表生成式中的节流规则类,则应该是来自throttle_classes变量中,而此变量里面则存放的是配置文件。当我们在局部使用时,可以在类中定义
类字段throttle_classes,如果全局使用,则在配置文件,REST_FRAMWORK变量中定义
3.2、循环拿到每一个节流规则类的对象后,需要去执行allow_request方法,所以,我们在自定义节流规则类的时候,必须要实现这个方法
如果执行allow_request方法返回了false,则需要执行每个自定义节流规则类的wait方法,所以这个方法我我们也必须要实现。

3.3、果然,get_throttles方法内部就是列表生成式和throttle_classes变量,配置文件的定义


4、当我们熟悉了前面的认证、权限流程,节流的流程就显得很简单了
三、内置的节流规则
我们自定义的节流规则,利用用户访问时带过来的IP地址做限制标识,在rest_framework中有内置的节流规则类,和我们的思路是一样的
我们可以直接使用,内置节流规则SimpleRateThrottle,我们可以继承它,来完成,功能实现。一起来看看他的源码和我们的是一样吗。
1 class VisitThrottles(SimpleRateThrottle): 2 scope = "Luffy" 3 4 def get_cache_key(self, request, view): 5 return self.get_ident(request)
1、我们在源码流程中知道,要实现节流的限制,必须要实现allow_request方法和wait方法,查看SimpleRateThrottle看看也确实现了这两种方法

2、首先这个内置的节流规则类已经可以完成基本的要求,那么我们再来详细看看他的实现过程,首先,在此类中的inint构造方法中,通过反射执行了get_rate方法,
查看此方法,发现,我们在使用这个内置规则是,要求我们必须要声明scope类变量,通过此变量来寻找配置文件中限制的规则。意思是可以通过用户自定义限制频率,
例如:用户要求的访问频次为每分钟访问10次。那么我们在配置文件中设置【"test":"10/m"】,那么怎么才能知道用户设置的频次呢,就是通过“test”这个标识来寻找
所以,此时设置的scope="test"
当然一般都是在配置文件,不可能每次都来修改源码文件。

2.1、可以通过设置不同的变量来满足不同视图的访问频次

3、继续往下看构造方法还干了什么。执行了parse_rate方法,并把获取到的类变量scope的值封装在self.rate传了进去。很明显返回了两个值。
看看parse_rate方法,中,将获取到的值,以‘/’作为分割出来了,下面并通过对应的字符串的首字母来进行时间的划分,查看用户是以天、时、分、秒来作为划分的
并且返回了,两个值,第一个是频次,第二个是时间单位对应的秒数。看到这里我们就要明白,用户在书写频率的时候,必须要按照“数字/时间单位”这中形式,不然无法划分识别。

4、通过前面的源码流程,我们知道当请求进来,通过了,认证、权限,下一步走节流限制,进入源码流程实例化了节流规则类的对象后,第一个执行的就是方法是allow_request
那我们在看看内置规则中的allow_request。

4.1、回头看,我们继承此方法时,所必须写的方法。这里执行了,get_ident方法,通过前面,我们知道这个方法,是获取IP作为标识来做节流限制的。
查看的方法,通过类的继承去一层一层找吧

5、通过用户设定的访问频率和标识,使用完全内置的方法来做节流规则。

6、通过完全内置的方法,我们只需要写4行代码即可实现,节流功能。
7、匿名用户,通过get_ident方法来获取IP作为标识,做节流限制。登录用户我们可以用token来进行限制
我们需要做的只是在继承的类中,重写我们的get_ident方法。获取缓存中,用户登录后的token,即可。


浙公网安备 33010602011771号