07 drf源码剖析之节流

1. 节流简述

  • 节流类似于权限,它确定是否应授权请求。节流指示临时状态,并用于控制客户端可以向API发出的请求的速率。

  • 还有情况可能是 ,由于某些服务特别耗费资源,因此您需要在API的不同部分施加不同的约束。

  • 频率限制在认证、权限之后

2. 节流使用

  • 在settings配置文件中设置规定时间段内可以访问的次数

    REST_FRAMEWORK = {
    "DEFAULT_THROTTLE_RATES": {"anon": '10/m'},
    }
  • 在需要节流的类中加throttle_classes

    from rest_framework.views import APIView
    from rest_framework.response import Response from rest_framework.throttling import AnonRateThrottle,BaseThrottle class ArticleView(APIView):
    throttle_classes = [AnonRateThrottle,]
    def get(self,request,*args,**kwargs):
    return Response('文章列表') class ArticleDetailView(APIView):
    def get(self,request,*args,**kwargs):
    return Response('文章列表')

3. 源码剖析

  • 请求过来先执行dispatch方法

    class APIView(View):
    permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES def dispatch(self, request, *args, **kwargs):
    # 封装request对象...
    self.initial(request, *args, **kwargs)
    # 通过反射执行视图中的方法...
  • initial方法过渡

    def initial(self, request, *args, **kwargs):
    # 版本的处理...
    # 认证...
    # 权限判断 self.check_throttles(request) # 节流
  • 将所有的节流类实例化成对象列表

    def get_throttles(self):
    return [throttle() for throttle in self.throttle_classes]
  • 循环执行每个对象的allow_request方法

    def check_throttles(self, request):
    throttle_durations = []
    for throttle in self.get_throttles():
    if not throttle.allow_request(request, self):
    throttle_durations.append(throttle.wait())
  • 执行allow_request方法,AnonRateThrottle没有allow_request,去父类找

    class AnonRateThrottle(SimpleRateThrottle):
    scope = 'anon' def get_cache_key(self, request, view):
    if request.user.is_authenticated:
    return None # Only throttle unauthenticated requests. return self.cache_format % {
    'scope': self.scope,
    'ident': self.get_ident(request)
    }
  • 执行SimpleRateThrottle类中allow_request方法

    • 获取请求用户的IP
    • 根据IP获取他的所有访问记录
    • 获取当前时间
    • 将不在规定时间的记录删除掉
    • 判断规定时间段时间内访问了多少次
    • 和设定次数对比,判断用户是否可以继续访问
    class SimpleRateThrottle(BaseThrottle):
    cache = default_cache
    timer = time.time
    cache_format = 'throttle_%(scope)s_%(ident)s'
    scope = None
    THROTTLE_RATES = api_settings.DEFAULT_THROTTLE_RATES def __init__(self):
    if not getattr(self, 'rate', None):
    self.rate = self.get_rate()
    self.num_requests, self.duration = self.parse_rate(self.rate) def parse_rate(self, rate):
    if rate is None:
    return (None, None)
    num, period = rate.split('/')
    num_requests = int(num)
    duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]
    return (num_requests, duration) def allow_request(self, request, view):
    if self.rate is None:
    return True # 获取请求用户的IP
    self.key = self.get_cache_key(request, view)
    if self.key is None:
    return True # 根据IP获取他的所有访问记录,[]
    self.history = self.cache.get(self.key, []) self.now = self.timer() while self.history and self.history[-1] <= self.now - self.duration:
    self.history.pop()
    if len(self.history) >= self.num_requests:
    return self.throttle_failure()
    return self.throttle_success() def throttle_success(self):
    self.history.insert(0, self.now)
    self.cache.set(self.key, self.history, self.duration)
    return True def throttle_failure(self):
    return False def wait(self):
    if self.history:
    remaining_duration = self.duration - (self.now - self.history[-1])
    else:
    remaining_duration = self.duration available_requests = self.num_requests - len(self.history) + 1
    if available_requests <= 0:
    return None return remaining_duration / float(available_requests)

总结:

  • 实现原理

    来访问时:

    1.获取当前时间 100121280

    2.100121280-60 = 100121220,小于100121220所有记录删除

    3.判断1分钟以内已经访问多少次了? 4

    4.无法访问

    停一会

    来访问时:

    1.获取当前时间 100121340

    2.100121340-60 = 100121280,小于100121280所有记录删除

    3.判断1分钟以内已经访问多少次了? 0

    4.可以访问
  • 具体流程
    1. 请求来时会执行allow_follow方法,
    2. 会用self.key获取请求用户的ip,再用self.history根据用户的ip获取其访问的记录,
    3. 获取当前的时间,用当前的时间减去设定的时间段,
    4. 循环该用户访问的记录,将不在该时间段的记录pop掉,
    5. 通过len判定该时间段已经访问了多少次,超过限定次数会返回false
    6. 匿名用户是通过ip进行访问限制,登录用户通过用户的id进行访问限制

07 drf源码剖析之节流的更多相关文章

  1. drf源码剖析系列(系列目录)

    drf源码剖析系列(系列目录) 01 drf源码剖析之restful规范 02 drf源码剖析之快速了解drf 03 drf源码剖析之视图 04 drf源码剖析之版本 05 drf源码剖析之认证 06 ...

  2. 06 drf源码剖析之权限

    06 drf源码剖析之权限 目录 06 drf源码剖析之权限 1. 权限简述 2. 权限使用 3.源码剖析 4. 总结 1. 权限简述 权限与身份验证和限制一起,决定了是否应授予请求访问权限. 权限检 ...

  3. 05 drf源码剖析之认证

    05 drf源码剖析之认证 目录 05 drf源码剖析之认证 1. 认证简述 2. 认证的使用 3. 源码剖析 4. 总结 1. 认证简述 当我们通过Web浏览器与API进行交互时,我们可以登录,然后 ...

  4. 04 drf源码剖析之版本

    04 drf源码剖析之版本 目录 04 drf源码剖析之版本 1. 版本简述 2. 版本使用 3.源码剖析 4. 总结 1. 版本简述 API版本控制使您可以更改不同客户端之间的行为.REST框架提供 ...

  5. 02 drf源码剖析之快速了解drf

    02 drf源码剖析之快速了解drf 目录 02 drf源码剖析之快速了解drf 1. 什么是drf 2. 安装 3. 使用 3. DRF的应用场景 1. 什么是drf drf是一个基于django开 ...

  6. 07 flask源码剖析之用户请求过来流程

    07 Flask源码之:用户请求过来流程 目录 07 Flask源码之:用户请求过来流程 1.创建ctx = RequestContext对象 2. 创建app_ctx = AppContext对象 ...

  7. drf源码分析系列---节流(访问频率限制)

    使用 from rest_framework.throttling import AnonRateThrottle from rest_framework.generics import ListAP ...

  8. 01 drf源码剖析之restful规范

    01 restful规范 目录 01 restful规范 1. 什么是restful规范 2.restful规范详细 1. 什么是restful规范 restful是一套规则,是程序间进行数据传输的一 ...

  9. DRF源码系列分析

    DRF源码系列分析 DRF源码系列分析--版本 DRF源码系列分析--认证 DRF源码系列分析--权限 DRF源码系列分析--节流

随机推荐

  1. matplotlib浅析

    首先放出matplotlib的中英文文档: 中文:https://www.matplotlib.org.cn/ 英文:https://matplotlib.org/3.1.1/index.html M ...

  2. laravel向视图传递变量

    向视图中传递变量 我们在开发web应用当中,通常都不是为了写静态页面而生的,我们需要跟数据打交道,那么这个时候,问题就来了,在一个MVC的框架中,怎么将数据传给视图呢?比如我们要在 ArticleCo ...

  3. 浅谈async 及 await

    async 及 await 涉及面试题:async 及 await 的特点,它们的优点和缺点分别是什么?await 原理是什么? 一个函数如果加上 async ,那么该函数就会返回一个 Promise ...

  4. cb52a_c++_STL_堆排序算法make_push_pop_sort_heap

    cb52a_c++_STL_堆排序算法make_push_pop_sort_heapheapsort堆排序算法make_heap()-特殊的二叉树,每一个节点都比根小,根就是最大的数.大根堆,也可以做 ...

  5. vue-drag-resize 可拖拽可缩放的标签,如何管理多个拖拽元素之间的zIndex?操作上需要保持当前激活的组件是最上层,但是在总体上,又要确保其图层管理的顺序。

    麻烦总是不断出现,还好办法总比困难多, 1.公司开发一款可视化编辑html网页的多媒体编辑平台,牵扯到标签元素的拖拽,缩放,我找了找方法发现原生技术实现起来代码太多,麻烦,还好找到了一个vue组件,可 ...

  6. opencv Scalar

    template<typename _Tp> class Scalar_ : public Vec<_Tp, 4> { public: //! various construc ...

  7. Centos7下的MySQL5.6安装

    yum install wget yum install perl perl-devel cd /usr/local/src wget https://cdn.mysql.com//Downloads ...

  8. 尚学堂 208.Annotation注解和内置注解

    208.Annotation注解和内置注解 override:这个注释的作用是标识某一个方法是否覆盖了它的父类的方法deprecated:表示果某个类成员的提示中出现了个词,就表示这个并不建议使用这个 ...

  9. android 6.0 以上在doze模式精确定时

    public static void start12hAlarm() { int seconds = TIMERLENGTH; ECMLog.i_ecms(CLASS_TAG, " star ...

  10. springboot_自动配置原理

    目录 1.1 @SpringBootApplication 2.1 @EnableAutoConfiguration 2.1.1 @AutoConfigurationPackage 2.1.2 @Im ...