翼度科技»论坛 编程开发 python 查看内容

DRF-Throttle组件源码分析及改编源码

6

主题

6

帖子

18

积分

新手上路

Rank: 1

积分
18
1. 限流组件源码分析

注意:以下源码为方便理解已进行简化,只保留了与限流组件相关的代码。注释前的数字代表执行顺序。


SimpleRateThrottle类的源码解析:

2. 实践:编写一个限流类
  1. from rest_framework.throttling import SimpleRateThrottle
  2. from django.core.cache import cache as default_cache
  3. class IpThrottle(SimpleRateThrottle):
  4.     scope = "ip"  # 节流类的名称
  5.     # THROTTLE_RATES = {"x1": "5/m"}   类中未定义THROTTLE_RATES则去settings中获取
  6.     cache = default_cache  # 节流类指定写入的缓存
  7.     def get_cache_key(self, request, view):
  8.         ident = self.get_ident(request)  # 获取请求用户IP(去request中找请求头)
  9.         return self.cache_format % {'scope': self.scope, 'ident': ident}
  10. class UserThrottle(SimpleRateThrottle):
  11.     scope = "user"  # 节流类的名称
  12.     # THROTTLE_RATES = {"x1": "5/m"}   类中未定义THROTTLE_RATES则去settings中获取
  13.     cache = default_cache  # 节流类指定写入的缓存
  14.     def get_cache_key(self, request, view):
  15.         ident = request.user.pk  # 用户ID
  16.         return self.cache_format % {'scope': self.scope, 'ident': ident}
复制代码
3. 源码改编


  • 重写限流的时长规则:原本只支持 1分钟x次,重写后支持 x分钟x次:
  1. def parse_rate(self, rate):
  2.         '''重写获取时长的parse_rate方法,原本只能写1/m或2/m,现在支持:1/5m, 3/10m的格式'''
  3.         if rate is None:
  4.                 return (None, None)
  5.         num, period = rate.split('/')  # "1/5m"
  6.         num_requests = int(num)
  7.         duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[-1]]
  8.         count = int(period[0:-1])
  9.         return (num_requests, duration * count)
复制代码



  • 请求操作失败时,不计入限流次数
  1. # 思路:在视图的操作成功后再进行计入操作(throttle_success)
  2. # 限流类中: 重写throttle_success操作,并把计次的操作提取出来,自定义一个函数,在视图操作成功后才调用该函数进行计次
  3. class MyThrottle(SimpleRateThrottle):
  4.        
  5.         def throttle_success(self):
  6.                 # self.history.insert(0, self.now)
  7.                 # self.cache.set(self.key, self.history, self.duration)
  8.                 return True
  9.         def done(self):
  10.                 """ 视图函数执行成功后,再调用throttle_success里的方法"""
  11.                 self.history.insert(0, self.now)
  12.                 self.cache.set(self.key, self.history, self.duration)
  13. # 视图类中:
  14. class MyView(APIView):
  15.         def post(request):
  16.         """中间代码省略"""
  17.         # 成功操作后才记录一次限流   
  18.         for throttle in self.get_throttles():
  19.                 throttle.done()
复制代码



  • 自定义限流类的报错信息
  1. # 在限流类中:
  2. # 自定义抛出报错的异常类
  3. class ThrottledException(exceptions.APIException):
  4.         status_code = status.HTTP_429_TOO_MANY_REQUESTS
  5.         default_code = 'throttled'
  6. #重写throttle_failure方法,自定义报错信息并直接抛出异常;
  7. def throttle_failure(self):
  8.         wait = self.wait()
  9.         detail = {
  10.                 "code": return_code.TOO_MANY_REQUESTS,
  11.                 "data": "访问频率限制",
  12.                 'detail': "需等待{}秒后才能访问".format(int(wait))
  13.         }
  14.         raise ThrottledException(detail)
复制代码
来源:https://www.cnblogs.com/harry6/p/18508725
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具