快速限流

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

  • 对于匿名用户,使用用户IP作为唯一标识。
  • 对于登录用户,使用用户ID或名称作为唯一标识。
  1. 缓存={
  2. 用户标识:[12:33,12:32,12:31,12:30,12,] 1小时/5 12:34 11:34
  3. {
  1. pip3 install django-redis

先启动redis
image.png
配置参考 https://pypi.org/project/django-redis/

  1. # settings.py
  2. CACHES = {
  3. "default": {
  4. "BACKEND": "django_redis.cache.RedisCache",
  5. "LOCATION": "redis://127.0.0.1:6379",
  6. "OPTIONS": {
  7. "CLIENT_CLASS": "django_redis.client.DefaultClient",
  8. "PASSWORD": "", # redis默认密码为空
  9. }
  10. }
  11. }
  1. # views.py
  2. from rest_framework.views import APIView
  3. from rest_framework.response import Response
  4. from rest_framework import exceptions
  5. from rest_framework import status
  6. from rest_framework.throttling import SimpleRateThrottle
  7. from django.core.cache import cache as default_cache
  8. class ThrottledException(exceptions.APIException):
  9. status_code = status.HTTP_429_TOO_MANY_REQUESTS
  10. default_code = 'throttled'
  11. class MyRateThrottle(SimpleRateThrottle):
  12. cache = default_cache # 访问记录存放在django的缓存中(需设置缓存)
  13. scope = "user" # 构造缓存中的key
  14. cache_format = 'throttle_%(scope)s_%(ident)s'
  15. # 设置访问频率,例如:1分钟允许访问10次
  16. # 其他:'s', 'sec', 'm', 'min', 'h', 'hour', 'd', 'day'
  17. THROTTLE_RATES = {"user": "10/m"}
  18. def get_cache_key(self, request, view):
  19. if request.user:
  20. ident = request.user.pk # 用户ID
  21. else:
  22. ident = self.get_ident(request) # 获取请求用户IP(去request中找请求头)
  23. # throttle_u # throttle_user_11.11.11.11ser_2
  24. return self.cache_format % {'scope': self.scope, 'ident': ident}
  25. def throttle_failure(self):
  26. wait = self.wait()
  27. detail = {
  28. "code": 1005,
  29. "data": "访问频率限制",
  30. 'detail': "需等待{}s才能访问".format(int(wait))
  31. }
  32. raise ThrottledException(detail)
  33. class OrderView(APIView):
  34. throttle_classes = [MyRateThrottle, ]
  35. def get(self, request):
  36. return Response({"code": 0, "data": "数据..."})

image.png

多个限流类

本质,每个限流的类中都有一个 allow_request 方法,此方法内部可以有三种情况

  • 返回True,表示当前限流类允许访问,继续执行后续的限流类。
  • 返回False,表示当前限流类不允许访问,继续执行后续的限流类。所有的限流类执行完毕后,读取所有不允许的限流,并计算还需等待的时间。
  • 抛出异常,表示当前限流类不允许访问,后续限流类不再执行。

注意:多个限流类,scope的值不能相同。

写法一(推荐)

所有的限流类执行完后,再返回报错

  1. # views.py
  2. from rest_framework.views import APIView
  3. from rest_framework.response import Response
  4. from rest_framework import exceptions
  5. from rest_framework import status
  6. from rest_framework.throttling import SimpleRateThrottle
  7. from django.core.cache import cache as default_cache
  8. class ThrottledException(exceptions.APIException):
  9. status_code = status.HTTP_429_TOO_MANY_REQUESTS
  10. default_code = 'throttled'
  11. class MyRateThrottle(SimpleRateThrottle):
  12. cache = default_cache # 访问记录存放在django的缓存中(需设置缓存)
  13. scope = "user" # 构造缓存中的key
  14. cache_format = 'throttle_%(scope)s_%(ident)s'
  15. # 设置访问频率,例如:1分钟允许访问10次
  16. # 其他:'s', 'sec', 'm', 'min', 'h', 'hour', 'd', 'day'
  17. THROTTLE_RATES = {"user": "10/m"}
  18. def get_cache_key(self, request, view):
  19. if request.user:
  20. ident = request.user.pk # 用户ID
  21. else:
  22. ident = self.get_ident(request) # 获取请求用户IP(去request中找请求头)
  23. # throttle_u # throttle_user_11.11.11.11ser_2
  24. return self.cache_format % {'scope': self.scope, 'ident': ident}
  25. class MyRateThrottleB(SimpleRateThrottle):
  26. cache = default_cache # 访问记录存放在django的缓存中(需设置缓存)
  27. scope = "xx" # 构造缓存中的key
  28. cache_format = 'throttle_%(scope)s_%(ident)s'
  29. # 设置访问频率,例如:1分钟允许访问3次
  30. # 其他:'s', 'sec', 'm', 'min', 'h', 'hour', 'd', 'day'
  31. THROTTLE_RATES = {"xx": "3/m"}
  32. def get_cache_key(self, request, view):
  33. if request.user:
  34. ident = request.user.pk # 用户ID
  35. else:
  36. ident = self.get_ident(request) # 获取请求用户IP(去request中找请求头)
  37. # throttle_u # throttle_user_11.11.11.11ser_2
  38. return self.cache_format % {'scope': self.scope, 'ident': ident}
  39. class OrderView(APIView):
  40. throttle_classes = [MyRateThrottle, ]
  41. def get(self, request):
  42. return Response({"code": 0, "data": "数据..."})
  43. def throttled(self, request, wait):
  44. detail = {
  45. "code": 1005,
  46. "data": "访问频率",
  47. 'detail': "需等待{}s才能访问".format(int(wait))
  48. }
  49. raise ThrottledException(detail)

写法二

前面的限流类执行完后,马上返回报错

  1. class ThrottledException(exceptions.APIException):
  2. status_code = status.HTTP_429_TOO_MANY_REQUESTS
  3. default_code = 'throttled'
  4. class MyRateThrottle(SimpleRateThrottle):
  5. cache = default_cache # 访问记录存放在django的缓存中(需设置缓存)
  6. scope = "user" # 构造缓存中的key
  7. cache_format = 'throttle_%(scope)s_%(ident)s'
  8. # 设置访问频率,例如:1分钟允许访问10次
  9. # 其他:'s', 'sec', 'm', 'min', 'h', 'hour', 'd', 'day'
  10. THROTTLE_RATES = {"user": "10/m"}
  11. def get_cache_key(self, request, view):
  12. if request.user:
  13. ident = request.user.pk # 用户ID
  14. else:
  15. ident = self.get_ident(request) # 获取请求用户IP(去request中找请求头)
  16. # throttle_u # throttle_user_11.11.11.11ser_2
  17. return self.cache_format % {'scope': self.scope, 'ident': ident}
  18. def throttle_failure(self):
  19. wait = self.wait()
  20. detail = {
  21. "code": 1005,
  22. "data": "访问频率限制",
  23. 'detail': "需等待{}s才能访问".format(int(wait))
  24. }
  25. raise ThrottledException(detail)
  26. class MyRateThrottleB(SimpleRateThrottle):
  27. cache = default_cache # 访问记录存放在django的缓存中(需设置缓存)
  28. scope = "xx" # 构造缓存中的key
  29. cache_format = 'throttle_%(scope)s_%(ident)s'
  30. # 设置访问频率,例如:1分钟允许访问10次
  31. # 其他:'s', 'sec', 'm', 'min', 'h', 'hour', 'd', 'day'
  32. THROTTLE_RATES = {"xx": "20/h"}
  33. def get_cache_key(self, request, view):
  34. if request.user:
  35. ident = request.user.pk # 用户ID
  36. else:
  37. ident = self.get_ident(request) # 获取请求用户IP(去request中找请求头)
  38. # throttle_u # throttle_user_11.11.11.11ser_2
  39. return self.cache_format % {'scope': self.scope, 'ident': ident}
  40. def throttle_failure(self):
  41. wait = self.wait()
  42. detail = {
  43. "code": 1005,
  44. "data": "访问频率限制",
  45. 'detail': "需等待{}s才能访问".format(int(wait))
  46. }
  47. raise ThrottledException(detail)
  48. class OrderView(APIView):
  49. throttle_classes = [MyRateThrottle, MyRateThrottleB]
  50. def get(self, request):
  51. return Response({"code": 0, "data": "数据..."})

image.png

全局配置

  1. REST_FRAMEWORK = {
  2. "DEFAULT_THROTTLE_CLASSES":["xxx.xxx.xx.限流类", ],
  3. "DEFAULT_THROTTLE_RATES": {
  4. "user": "10/m",
  5. "xx":"100/h"
  6. }
  7. }