django restframework学习笔记:限流组件

作用

限流,限制用户访问频率,例如:用户1分钟最多访问100次 或者 短信验证码一天每天可以发送50次, 防止盗刷。

  • 对于匿名用户,使用用户IP作为唯一标识。
  • 对于登录用户,使用用户ID或名称作为唯一标识。

思路

如何限制? 假如10分钟3次

“9123123”:[16:45, 16:43, 16:42]

1.获取当前时间 16:45

2.当前时间 - 10分钟 = 计数开始时间 16:35

3.删除小于计数时间的

4.计算长度 :超过,错误;未超过,访问

使用

SimpleRateThrottle直接实现了上面的限流思路,所以我们不继承Throttle而是直接继承SimpleRateThrottle方法。

限流需要记录每次成功访问接口的时间,所以需要缓存,我们这里设置redis为默认缓存并使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import exceptions
from rest_framework import status
from rest_framework.throttling import SimpleRateThrottle
from django.core.cache import cache as default_cache

class ThrottledException(exceptions.APIException):
status_code = status.HTTP_429_TOO_MANY_REQUESTS
default_code = 'throttled'


class MyRateThrottle(SimpleRateThrottle):
cache = default_cache # 访问记录存放在django的缓存中(需设置缓存)
scope = "user" # 构造缓存中的key
cache_format = 'throttle_%(scope)s_%(ident)s'

# 设置访问频率,例如:1分钟允许访问10次
# 其他:'s', 'sec', 'm', 'min', 'h', 'hour', 'd', 'day'
THROTTLE_RATES = {"user": "10/m"}

# 设置用户唯一的标识
def get_cache_key(self, request, view):
if request.user:
ident = request.user.pk # 登录了就拿用户ID
else:
ident = self.get_ident(request) # 没登录就获取请求用户IP(去request中找请求头)(get_ident自动获取代理前的ip地址)

return self.cache_format % {'scope': self.scope, 'ident': ident}

def throttle_failure(self):
wait = self.wait()
detail = {
"code": 1005,
"data": "访问频率限制",
'detail': "需等待{}s才能访问".format(int(wait))
}
raise ThrottledException(detail)

class OrderView(APIView):
throttle_classes = [MyRateThrottle, ] # 普通视图加这个就是启用了

1
2
def get(self, request):
return Response({"code": 0, "data": "数据..."})

缓存需要用到redis

1
pip3 install django-redis
1
2
3
4
5
6
7
8
9
10
11
 # settings.py
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"PASSWORD": "qwe123",
}
}
}