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. Ubuntu18.04 安装QQ、Tim、微信与win无差异

    一.安装deepin-wine环境: 桌面下打开终端,依次输入以下命令 git clone https://gitee.com/wszqkzqk/deepin-wine-for-ubuntu.git ...

  2. DML_Data Modification_MERGE

    DML_8-Data Modification_MERGE (将Source表合并到Target) 语法:MERGE INTO 目标表USING 源表WHEN MATCHED AND          ...

  3. Springboot打包放到Tomcat中报错 One or more listener fail to start

    1.问题: Springboot项目直接启动不报错,打war包放到外部容器Tomcat.东方通上,在@Weblistener注解的监听器类中报错 One or more listener fail t ...

  4. Arduino + RFID 读取 IC 卡 Arduino uno中获得RFID的UID 并通过串口转发RFID卡号

    RFID简介:射频识别即RFID(Radio Frequency IDentification)技术,又称无线射频识别,是一种通信技术,可通过无线电讯号识别特定目标并读写相关数据,而无需识别系统与特定 ...

  5. JavaWeb网上图书商城完整项目--day02-3.regist页面输入框失去焦点进行校验

    当输入框输入数据之后,当输入框失去焦点的时候,我们需要对输入的数据进行校验 l  用户名校验: 用户名不能为空: 用户名长度必须在3 ~ 20之间: 用户名已被注册(需要异步访问服务器). l  登录 ...

  6. 慕课网--docker走进第一个javaweb应用

    zh docker镜像就是一系列文件的集合 docker 容器就是一个进程.将docker镜像运行起来就是一个docker容器 docker仓库就是存储docker镜像的 1.docker的安装 do ...

  7. easymock笔记2

    EasyMock主要是为测试提供模拟数据,比如你可以模拟HttpServletRequest. EasyMock 可以mock interface和抽象java 类,但是不可以mock拥有被final ...

  8. 输入url后浏览器干了些什么(详解)

    输入url后浏览器干了些什么(详解) DNS(Domain Name System, 域名系统) 解析 DNS解析的过程就是寻找哪台机器上有你真正需要的资源过程.但你在浏览器张红输入一个地址时,例如: ...

  9. Idea集成git常用命令

    git status --查看文件状态   untracked: 未跟踪 一般为新增文件  git add 状态改为staged git add +文件 git add -A +路径  修改过的未被跟 ...

  10. 物联网SIM卡和SIM卡,真的不是一回事

    [摘要]在物联网解决方案中,设备移动上网也需要使用SIM卡.那么,SIM卡是什么?各种SIM卡有什么区别?物联网SIM卡如何选择?本文将为您答疑解惑. 通信进化史 过去几百年间,通信技术经历了天变地异 ...