作用 限流,限制用户访问频率,例如:用户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", } } }