开放平台的 API 接口调用需要限制其频率, 以节约服务器资源和避免恶意的频繁调用
使用
自定义频率限制组件: utils/thottle.py
- class MyThrottle(BaseThrottle):
- def __init__(self):
- self.history = None
- def allow_request(self, request, view):
- # 实现限流的逻辑
- # 以 IP 限流
- # 访问列表 {IP: [time1, time2, time3]}
- # 1, 获取请求的 IP 地址
- ip = request.META.get("REMOTE_ADDR")
- # 2, 判断 IP 地址是否在访问列表
- now = time.time()
- if ip not in VISIT_RECORD:
- # --1, 不在 需要给访问列表添加 key,value
- VISIT_RECORD[ip] = [now,]
- return True
- # --2 在 需要把这个 IP 的访问记录 把当前时间加入到列表
- history = VISIT_RECORD[ip]
- history.insert(0, now)
- # 3, 确保列表里最新访问时间以及最老的访问时间差 是 1 分钟
- while history and history[0] - history[-1]> 60:
- history.pop()
- self.history = history
- # 4, 得到列表长度, 判断是否是允许的次数
- if len(history)> 3:
- return False
- else:
- return True
- def wait(self):
- # 返回需要再等多久才能访问
- time = 60 - (self.history[0] - self.history[-1])
- return time
views.py
- class TestThrottle(APIView):
- throttle_classes = [MyThrottle, ]
- def get(self, request, *args, **kwargs):
- pass
allow_request() 方法内定义频率控制的实现
wait() 方法的返回值代表了距离下次允许访问还剩多久, 单位: 秒
全局使用
同样, 需要配置 setttings 文件
- REST_FRAMEWORK = {
- "DEFAULT_PERMISSION_CLASSES": [] # 默认的权限类
- }
使用 REST Framework 提供的频率控制组件
DRF 提供了四种频率控制组件:
- SimpleRateThrottle
- AnonRateThrottle
- UserRateThrottle
- ScopedRateThrottle
以 SimpleRateThrottle 为例:
settings.py
- REST_FRAMEWORK = {
- 'DEFAULT_THROTTLE_CLASSES':['api.utils.mythrottle.UserThrottle',]
- 'DEFAULT_THROTTLE_RATES': {
- '未认证用户': '10/m',
- '已认证用户': '100/h',
- },
- }
utils.thorttle.py
- from rest_framework.views import APIView
- from rest_framework.response import Response
- from rest_framework import exceptions
- from rest_framework.throttling import SimpleRateThrottle
- class VisitThrottle(SimpleRateThrottle):
- scope = "未认证用户"
- def get_cache_key(self, request, view):
- return self.get_ident(request)
- class UserThrottle(SimpleRateThrottle):
- scope = "已认证用户"
- def get_cache_key(self, request, view):
- return request.user # 认证通过后, 认证方法 authenticate 的返回值之一
views.py
- class TestThrottle(APIView):<br> # 这样设置后, 节流功能就会使用 VisitThrottle 类, 而不会使用 UserThrottle 类
- throttle_classes = [VisitThrottle,]
- def get(self, request, *args, **kwargs):
这里使用的节流类是继承了 SimplePateThrottle 类, 而这个类利用了 django 内置的缓存来存储访问记录. 通过全局节流设置, 所有的视图类默认是使用 UserThrottle 类进行节流, 如果不想使用默认的类就自定义给 throttle_classes 属性变量赋值, 如:"throttle_classes = [VisitThrottle,]".
源码分析
1. 为什么会使用 "scope" 属性变量, 它有什么用?
由内置接口代码基本结构中可以看到, 视图类 TestThrottle 继承了 SimpleRateThrottle 类, 跳转到这个类中, 就可以看到 scope 属性变量.
由 "THROTTLE_RATES[self.scope]" 知, scope 一定是一个 key 值, 而 THROTTLE_RATES 不就是在配置文件中所设置的变量吗? 所以说 scope 代表的就是 "未认证用户" 和 "已认证用户" 这两个 key 值, 而这两个 key 值代表的就是不同的节流方案. 返回值就这这两个 key 值所对应的 value 值, 具体是哪一个, 那就看视图类 TestTrottle 中对 scope 属性变量的值是什么了, 如果这个 scope 值不存在, 就会抛出异常.
2. 为什么会使用 "get_cache_key" 方法? 该方法的返回值是什么?
在分析 get_cache_key 方法前, 先分析一下 SimpleRateThrottle 类:
cache = default_cache 它表示的就是存储用户访问记录的缓存, 而这个缓存正是 django 默认的缓存.
get_rate 方法, 前面已经说过了, 是用来获取节流方式的.
parse_rate 方法, 解析节流方式
allow_request 方法, 就是跟在自定义节流方法一样, 是实现节流算法的. 之所以会用内置节流方法, 就是因为在这里, 已经实现了节流算法.
wait 方法, 就是跟在自定义节流类中的 wait 方法一样, 返回提示用户还有多长时间就可以再次访问了.
通过初始化方法, 获取并解析好要使用的节流方式, 供 allow_request 方法使用.
通过调用 check_throttles 方法, 来调用 allow_request 方法, 由上面关于 allow_request 截图来看, 要完成它的功能, 就必须通过 get_cache_key 方法获取到当前用户的唯一标识, 所以 get_cache_key 应该返回唯一标识.
get_cache_key 方法, 这就是在视图类 TestThrottle 中重写的方法. 由上图可知, 该方法是必须重写的, 不然就会抛出异常.
3. 为什么会使用 "throttle_classes" 属性变量, 它有什么用?
通过查看 dispatch 方法中的 intial 方法可以看到调用的节流方法 "check_throttles".
这个 for 循环返回的一定是一个列表, 类似于认证和授权的源码, 那么这个列表一定是保存节流类的列表.
get_throttles 方法返回的是一个列表生成式, 而这里的 throttle_classes 就是在视图类 TestThrottle 中使用的, 该变量就保存节流类对象.
4."DEAFULT_THROTTLE_CLASSES" 从哪里来? 有什么用?
通过 throttle_classes 属性变量, 跳转到该图, 可以看到配置文件中说的 "DEFAULT_THROTTLE_CLASSES", 它是用来通过配置文件 settings 来对全局节流类进行配置, 功能等价于 throttle_classes 属性变量
5."DEAFULT_THROTTLE_RATES" 从哪里来? 有什么用?
由 SimpleRateThrottle 类和上文对 scope 属性变量的分析可知, THROTTLE_RATES 就是为了存储在配置文件中设置的不同的节流方法的.
综上所述, 可以看出, 在利用内置节流接口时, 通过配置文件 settings 的设置和提供该接口所需的用户唯一标识外, 不需要我们做再多的操作, 这就形成了我们上文写的内置接口代码基本结构的样式.
来源: https://www.cnblogs.com/V587Chinese/p/11569065.html