手摸手,带你用Django REST Framework撸接口系列八(限流篇)
类似于[权限],限流器决定是否应当授权请求。限流器指示临时状态,并被用于控制客户端能够向API发出请求的频率。
Django REST Framework系列文章
- 手摸手,带你用Django REST Framework撸接口系列一(基础篇)
- 手摸手,带你用Django REST Framework撸接口系列二(序列化器篇)
- 手摸手,带你用Django REST Framework撸接口系列三(视图篇)
- 手摸手,带你用Django REST Framework撸接口系列四(渲染器篇)
- 手摸手,带你用Django REST Framework撸接口系列五(路由篇)
- 手摸手,带你用Django REST Framework撸接口系列六(认证篇)
- 手摸手,带你用Django REST Framework撸接口系列七(权限篇)
- 手摸手,带你用Django REST Framework撸接口系列八(限流篇)
- 手摸手,带你用Django REST Framework撸接口系列九(过滤篇)
- 手摸手,带你用Django REST Framework撸接口系列十(排序篇)
- 手摸手,带你用Django REST Framework撸接口系列十一(分页篇)
- 手摸手,带你用Django REST Framework撸接口系列十二(异常处理篇)
- 手摸手,带你用Django REST Framework撸接口系列十三(自动生成接口文档篇)
限流(Throttle)就是限制客户端对API 的调用频率,是API开发者必须要考虑的因素。比如个别客户端(比如爬虫程序)短时间发起大量请求,超过了服务器能够处理的能力,将会影响其它用户的正常使用。又或者某个接口占用数据库资源比较多,如果同一时间该接口被大量调用,服务器可能会陷入僵死状态。为了保证API服务的稳定性,并防止接口受到恶意用户的攻击,我们必须要对我们的API服务进行限流。
DRF中限制对API的调用频率非常简便,它为我们主要提供了3个可插拔使用的限流类,分别是AnonRateThrottle
, UserRateThrottle
和ScopeRateThrottle
类。
- AnonRateThrottle 用于限制未认证用户的请求频率,主要根据用户的 IP地址来确定用户身份。
- UserRateThrottle 用于限定认证用户的请求频率,可对不同类型的用户实施不同的限流政策。
- ScopeRateThrottle可用于限制对 API 特定部分的访问。只有当正在访问的视图包含
throttle_scope
属性时才会应用此限制。这个与UserRateThrottle类的区别在于一个针对用户限流,一个针对API接口限流。
DRF限制频率的指定格式为 “最大访问次数/时间间隔”,例如设置为 5/min,则只允许一分钟内最多调用接口 5 次。其它常用格式包括”10/s”, “100/d”等。超过限定次数的调用将抛出 exceptions.Throttled
异常,客户端收到 429 状态码(too many requests)的响应。
全局限流
通过使用 DEFAULT_THROTTLE_CLASSES
和 DEFAULT_THROTTLE_RATES
默认限流策略将被全局设定,例如:
1 | REST_FRAMEWORK = { |
被用于 DEFAULT_THROTTLE_RATES
中的流量描述可能包括 second
, minute
, hour
or day
作为限流周期
局部限流
对于基于 APIView
类的视图,您可以以每个视图或每个视图集为基础设置限流策略
1 | from rest_framework.response import Response |
或者,如果您使用带有 @api_view
装饰器的基于函数的视图
1 |
|
视图类或视图集中使用限流类
DRF中还可以在单个视图或单个视图集中进行限流配置,单个视图中的配置会覆盖全局设置。现在我们希望保留settings.py
的限流全局配置,并专门为文章资源列表/v1/articles定制一个限流类,新的访问频率限制为匿名用户为”5/min”, 认证用户为”30/min”,该配置仅对文章资源列表这个接口生效。
我们首先在app文件夹blog目录下新建throttles.py
, 添加如下代码:
1 | from rest_framework.throttling import AnonRateThrottle, UserRateThrottle |
我们通过继承自定义了ArticleAnonRateThrottle
, ArticleUserRateThrottle
两个类,并通过THROTTLE_RATES属性设置了新的访问频率限制。现在我们可以将它们应用到views.py中对应文章资源列表的API视图类。无需重启测试服务器,你将发现新的限流设置已经生效了。
1 | class ArticleView(viewsets.ModelViewSet): |
有时对一个认证用户进行限流不仅要限制每分钟的请求次数,还需要限制每小时的请求次数,这时该如何操作呢? 我们可以自定义两个UserRateThrottle
子类,并设置不同的scope,如下所示:
1 | from rest_framework.throttling import UserRateThrottle |
视图类中换上我们自定义的限流类
1 | throttle_classes = (MinuteUserRateThrottle, HourUserRateThrottle) |
此时第一分钟内我们可以访问5次,超过5次会被限流,一分钟过后可以继续访问,一小时内访问次数超过10次,又会被限流。
ScopeRateThrottle类
AnonRateThrottle和UserRateThrottle类都是针对单个用户请求进行限流的,而ScopeRateThrottle类是针对不同API接口资源进行限流的,限制的是所有用户对接口的访问总数之和。使用时直接在视图类里通过throttle_scope
属性指定限流范围(scope), 然后在settings.py对不同scope设置限流频率。例子如下所示:
1 | class ArticleView(viewsets.ModelViewSet): |
针对不同api接口设置不同限流频率。如下配置代表文章资源每分钟限10次请求(所有用户访问数量之和),用户资源接口限每分钟5次。
1 | REST_FRAMEWORK = { |
自定义限流类
有时你还需要自定义限流类。这时你需要继承BaseThrottle类、SimpleRateThrottle或者UserRateThrottle类,然后重写allow_request(self, request, view)
或者get_rate(self, request=none)
方法。DRF给的示例方法如下所示,该限流类10个请求中只允许一个通过。
若要创建自定义限流器,请重写 BaseThrottle
并使用 .allow_request(self, request, view)
。如果允许请求,则该方法应返回 True
,否则返回 False
。
你也可以选择性地重写 .wait()
方法。如果被使用,.wait()
应返回尝试下一个请求前建议的等待秒数,或者 None
。只有在 .allow_request()
先前已返回 False
时才会调用 .wait()
方法。
如果使用了 .wait()
方法并限制了请求,则响应中将包含 Retry-After
头。
以下例子为每10个请求中随机限制一个请求
1 | import random |
Django REST Framework系列文章
- 手摸手,带你用Django REST Framework撸接口系列一(基础篇)
- 手摸手,带你用Django REST Framework撸接口系列二(序列化器篇)
- 手摸手,带你用Django REST Framework撸接口系列三(视图篇)
- 手摸手,带你用Django REST Framework撸接口系列四(渲染器篇)
- 手摸手,带你用Django REST Framework撸接口系列五(路由篇)
- 手摸手,带你用Django REST Framework撸接口系列六(认证篇)
- 手摸手,带你用Django REST Framework撸接口系列七(权限篇)
- 手摸手,带你用Django REST Framework撸接口系列八(限流篇)
- 手摸手,带你用Django REST Framework撸接口系列九(过滤篇)
- 手摸手,带你用Django REST Framework撸接口系列十(排序篇)
- 手摸手,带你用Django REST Framework撸接口系列十一(分页篇)
- 手摸手,带你用Django REST Framework撸接口系列十二(异常处理篇)
- 手摸手,带你用Django REST Framework撸接口系列十三(自动生成接口文档篇)