5.频率控制

5.1频率监控代码实现

  1. import time
  2. VISIT_RECORD = {}
  3. class VisitThrottle(object):
  4. def __init__(self):
  5. #定义历史记录,生产环境上,应该将其保存在redis
  6. self.history = []
  7. def allow_request(self,request,view):
  8. #1.获取用户IP
  9. remote_addr = request._request.META.get("REMOTE_ADDR")
  10. print(remote_addr)
  11. #记录访问时的时间
  12. ctime = time.time()
  13. #判断当前IP是否在访问记录中
  14. if remote_addr not in VISIT_RECORD:
  15. VISIT_RECORD[remote_addr] = [ctime,]
  16. return True
  17. #拿取当前访问IP记录
  18. history = VISIT_RECORD.get(remote_addr)
  19. #将历史访问时间记录,复制给self.history,以方便wait方法调用,通过wait方法告诉用户一些信息
  20. self.history = history
  21. #逻辑判断只记录1分钟内访问记录。
  22. while history and history[-1] < ctime-60:
  23. history.pop()
  24. #访问历史列表中时间记录不能大于3
  25. if len(history) < 3:
  26. history.insert(0,ctime)
  27. return True
  28. def wait(self):
  29. """用于提示多少秒后才可以重新访问"""
  30. #记录当前时间
  31. ctime = time.time()
  32. #返回告知用户还有多长时间可以再次访问
  33. return 60-(ctime - self.history[-1])
  34. class AuthView(APIView):
  35. #用于频率限制
  36. throttle_classes = [VisitThrottle,]
  37. def post(self,request,*args,**kwargs):
  38. ret = {"code":1000,"msg":None}
  39. return JsonResponse(ret)
  • 效果:

    当发送请求在监测频率范围内:

    当发送请求超出监测频率范围:返回信息提示,此信息提示为wait定义的。

5.2频率表权限源码解析

  1. def dispatch(self, request, *args, **kwargs):
  2. ...
  3. try:
  4. #执行initial方法
  5. self.initial(request, *args, **kwargs)
  6. ...
  7. #---------------------------------------------------------
  8. def initial(self, request, *args, **kwargs):
  9. ...
  10. self.check_throttles(request)#用于限制频率
  11. ...
  12. #---------------------------------------------------------
  13. def check_throttles(self, request):
  14. throttle_durations = []
  15. #遍历 循环get_throttles
  16. for throttle in self.get_throttles():
  17. #如果allow_request返回False,则拒绝访问,并执行wait方法,抛出提示用户信息
  18. if not throttle.allow_request(request, self):
  19. throttle_durations.append(throttle.wait())
  20. if throttle_durations:
  21. self.throttled(request, max(throttle_durations))
  22. #---------------------------------------------------------
  23. def get_throttles(self):
  24. #实例化返回一个列表,当用户定义throttle_classes,则返回用户定义的[对象,对象...]
  25. #如果用户没有定义,将使用django内置配置:throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES
  26. return [throttle() for throttle in self.throttle_classes]

5.3全局和局部配置权限:

  1. #全局配置settings.py
  2. REST_FRAMEWORK={
  3. 'DEFAULT_THROTTLE_CLASSES':['app.utils.throttle.VisitThrottle']
  4. }
  5. #局部配置
  6. 类下面定义throttle_classes =[频率监测类,]

5.4内置频率类

  1. class BaseThrottle:
  2. def allow_request(self, request, view):
  3. """
  4. 如果应该允许请求,则返回True,否则返回False。
  5. """
  6. raise NotImplementedError('.allow_request() must be overridden')
  7. def get_ident(self, request):
  8. """
  9. 通过解析HTTP_X_FORWARDED_FOR(如果存在且代理数> 0)来识别发出请求的机器。如果不可用,则使用所有HTTP_X_FORWARDED_FOR(如果可用),如果不使用,则不使用REMOTE_ADDR
  10. """
  11. xff = request.META.get('HTTP_X_FORWARDED_FOR')
  12. remote_addr = request.META.get('REMOTE_ADDR')
  13. num_proxies = api_settings.NUM_PROXIES
  14. if num_proxies is not None:
  15. if num_proxies == 0 or xff is None:
  16. return remote_addr
  17. addrs = xff.split(',')
  18. client_addr = addrs[-min(num_proxies, len(addrs))]
  19. return client_addr.strip()
  20. return ''.join(xff.split()) if xff else remote_addr
  21. def wait(self):
  22. """
  23. (可选)返回建议的秒数,以等待下一个请求
  24. """
  25. return None
  26. #BaseThrottle定义了get_ident用于获取访问用户ID,这样可以自定义频率监测类继承BaseThrottle,通过调用父类方法,获取访问用户ID
  27. remote_addr = self.get_ident(request)
  28. #------------------------------------------------------------------------------------------------
  29. class SimpleRateThrottle(BaseThrottle):
  30. """一个简单的缓存实现,只需要覆盖.get_cache_key()即可。速率(请求/秒)由View类的“ rate”属性设置。该属性是形式为'number_of_requests / period'的字符串。周期应为以下之一:('s','sec','m','min','h','hour','d','day')用于限制的先前请求信息存储在缓存中"""
  31. cache = default_cache
  32. timer = time.time
  33. cache_format = 'throttle_%(scope)s_%(ident)s'
  34. scope = None
  35. THROTTLE_RATES = api_settings.DEFAULT_THROTTLE_RATES
  36. def __init__(self):
  37. if not getattr(self, 'rate', None):
  38. self.rate = self.get_rate()
  39. #num_requests表示次数,duration表示秒/分数
  40. self.num_requests, self.duration = self.parse_rate(self.rate)
  41. def get_cache_key(self, request, view):
  42. """
  43. 应该返回一个唯一的可用于节流的缓存键。必须重写。如果不应该限制请求,则可能会返回“无”
  44. """
  45. raise NotImplementedError('.get_cache_key() must be overridden')
  46. def get_rate(self):
  47. """
  48. 确定允许请求速率
  49. """
  50. if not getattr(self, 'scope', None):
  51. msg = ("You must set either `.scope` or `.rate` for '%s' throttle" %
  52. self.__class__.__name__)
  53. raise ImproperlyConfigured(msg)
  54. try:
  55. return self.THROTTLE_RATES[self.scope]
  56. except KeyError:
  57. msg = "No default throttle rate set for '%s' scope" % self.scope
  58. raise ImproperlyConfigured(msg)
  59. def parse_rate(self, rate):
  60. """
  61. 给定请求速率字符串
  62. """
  63. if rate is None:
  64. return (None, None)
  65. num, period = rate.split('/')
  66. num_requests = int(num)
  67. duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]
  68. return (num_requests, duration)
  69. def allow_request(self, request, view):
  70. """
  71. Implement the check to see if the request should be throttled.
  72. On success calls `throttle_success`.
  73. On failure calls `throttle_failure`.
  74. """
  75. if self.rate is None:
  76. return True
  77. # 将访问者信息放在缓存中
  78. self.key = self.get_cache_key(request, view)
  79. if self.key is None:
  80. return True
  81. #从缓存拿历史记录, cache = default_cache为Django内置缓存
  82. self.history = self.cache.get(self.key, [])
  83. self.now = self.timer()
  84. # Drop any requests from the history which have now passed the
  85. # throttle duration
  86. while self.history and self.history[-1] <= self.now - self.duration:
  87. self.history.pop()
  88. if len(self.history) >= self.num_requests:
  89. return self.throttle_failure()
  90. return self.throttle_success()
  91. def throttle_success(self):
  92. #成功返回
  93. """
  94. Inserts the current request's timestamp along with the key
  95. into the cache.
  96. """
  97. self.history.insert(0, self.now)
  98. self.cache.set(self.key, self.history, self.duration)
  99. return True
  100. def throttle_failure(self):
  101. #失败返回
  102. """
  103. Called when a request to the API has failed due to throttling.
  104. """
  105. return False
  106. def wait(self):
  107. """
  108. 返回建议的下一个请求时间(以秒为单位)。
  109. """
  110. if self.history:
  111. remaining_duration = self.duration - (self.now - self.history[-1])
  112. else:
  113. remaining_duration = self.duration
  114. available_requests = self.num_requests - len(self.history) + 1
  115. if available_requests <= 0:
  116. return None
  117. return remaining_duration / float(available_requests)
  118. #SimpleRateThrottle 内置分装好了监测频率各种(成功返回,错误返回,定义访问频次,返回下一次请求时间,确定速率等)方法。这样我们自己定义类继承SimpleRateThrottle
  119. #更改自定义频率监测:
  120. class VisitThrottle(SimpleRateThrottle):
  121. scope = "key"#根据scope的值,去配置文件找频率设置
  122. def get_cache_key(self, request, view):
  123. return self.get_ident(request)
  124. #settings.py配置
  125. REST_FRAMEWORK={
  126. 'DEFAULT_THROTTLE_CLASSES':['app.utils.throttle.VisitThrottle'],
  127. "DEFAULT_THROTTLE_RATES":{
  128. #设置频率3/m表示每分钟最多访问3次,并给予标识
  129. 'key':'3/m'
  130. }
  131. }

5.5对当前登录用户进行操作

  1. #settings.py配置
  2. REST_FRAMEWORK={
  3. 'DEFAULT_THROTTLE_CLASSES':['app.utils.throttle.VisitThrottle'],
  4. "DEFAULT_THROTTLE_RATES":{
  5. 'key':'3/m',
  6. #用于登录用户频率监测配置设置
  7. 'vipkey':'10/m',
  8. }
  9. }
  10. #throttle.py
  11. #定义登录用户频次监测类
  12. class UserThrottle(SimpleRateThrottle):
  13. scope = "vipkey"
  14. def get_cache_key(self, request, view):
  15. #返回登录用户名
  16. return request.user.username
  17. #因定义登录用户检测的类,不能放入settings配置,应予以局部添加
  18. class OrderView(APIView):
  19. throttle_classes = [UserThrottle, ]

5.6小总结:

  1. 基本使用:
  2. 继承:BaseThrottle 实现:allow_request,wait 方法
  3. 继承:SimpleRateThrottle 实现:get_cache_key ,scope (配置文件中的key,去找频率设置)

Django:RestFramework之-------频率控制的更多相关文章

  1. rest-framework之频率控制

    rest-framework之频率控制 本文目录 一 频率简介 二 自定义频率类,自定义频率规则 三 内置频率类及局部使用 四 内置频率类及全局使用 五 源码分析 回到目录 一 频率简介 为了控制用户 ...

  2. django restframework serializer 增加自定义字段

    在使用django restframework serializer 序列化在django中定义的model时,有时候我们需要额外在serializer中增加一些model中没有的字段.有两种方法实现 ...

  3. django restframework

    一.django restframework 请求流程源码剖析 上面的认证一个流程是rest_framework的关于APIauth的认证流程,,这个流程试用权限.频率.版本.认证.这个四个组件都是通 ...

  4. django restframework jwt

    既然要来学习jwt(json web token),那么我们肯定是先要了解jwt的优势以及应用场景--跨域认证. $ pip install djangorestframework-jwt 传统coo ...

  5. django restframework 快速入门

    django restframework 快速入门 基本流程 建立 Models 依靠 Serialiers 将数据库取出的数据 Parse 为 API 的数据(可用于返回给客户端,也可用于浏览器显示 ...

  6. Django Restframework 实践(一)

    具备以下知识: django http://www.cnblogs.com/menkeyi/p/5882464.html http://www.cnblogs.com/menkeyi/p/588245 ...

  7. django: rest-framework的 分页和过滤

    django: rest-framework的 分页和过滤 2018年06月28日 10:09:01 weixin_42359464 阅读数:136 标签: flaskrestframeworkdja ...

  8. django restframework 的日常使用

    本文讨论 django restframework 的日常使用,满足常用 api 编写的需求,比如 List, Detail, Update, Put, Patch 等等.探讨 django rest ...

  9. Django RestFramework (DRF)

    准备: 下载 pip install djangorestframework 一 APIView源码解析 1 预备知识 CBV(class based view)FBV(function based ...

随机推荐

  1. java Atomic compareAndSet部分原理分析

    以AtomicLong的compareAndSet方法举例.先说结论:如果CPU支持,则基于CPU指令(CMPXCHG8)实现:否则使用ObjectLocker锁实现. 分析过程如下: 该方法在jdk ...

  2. 201871010126 王亚涛 《面向对象程序设计(java)》 第二周学习总结

    项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...

  3. linux 指定用户 启动 程序

    sudo -H -u {username} /bin/bash -c "python test.py &" "&"  后台运行指令 本人亲测可用 ...

  4. blocking cache和non-blocking cache

    - a Blocking Cache will not accept any more request until the miss is taken care of. - a Non-blockin ...

  5. matlab-层次分析法

    层次分析法(AHP)是把问题条理化.层次化,构造出一个有层次的结构模型的方法. 比如要选择旅游地,有3个选择方案,苏杭.北戴河和桂林.选择过程需要考虑多个因素,比如景色.费用.居住.饮食和旅途. 1. ...

  6. Qt常用类——QWidget

    QWidget类是所有用户界面对象的基类. Widget是用户界面的基本单元:它从窗口系统接收鼠标,键盘和其他事件,并在屏幕上绘制自己. 每个Widget都是矩形的,它们按照Z-order进行排序.

  7. LOJ2778 [BOI2018]基因工程 随机化

    题面 不想写了...留坑吧... 基本思想可参照随机化解决判同问题的总结 代码: #include<bits/stdc++.h> using namespace std; #define ...

  8. mac 下使用nasm

    #安装nasm brew install nasm #创建文件 vi hello.asm 写入如下内容 msg: db "hello world!", 0x0a len: equ ...

  9. Android Studio 之 ROM【3】,LiveData+ViewModel+AsyncTask+Repository+RecyclerView

    教程地址:https://www.bilibili.com/video/av65180549 源码地址:https://github.com/longway777/Android-2019-Tutor ...

  10. ping-pong buffer

    1 什么是pingpong? pingpong是一种数据缓存的手段,通过pingpong操作可以提高数据传输的效率. 2 什么时候需要pingpong? 在两个模块间交换数据时,上一级处理的结果不能马 ...