正在进入ing...

Django DRF之限流

发布时间:2023-01-27 浏览量: 449 文章分类: python

这个玩意怎么说呢,其实之前我没有太重视,因为我觉得本身反爬就是博弈的过程,对面完全可以用代理IP、批量注册等方式实现抓取想要的内容。直到最近我发现我错了。在公司内部的一个团队使用的小项目,总是机器疯狂报实例100%使用。每次排查都发现接口被几个IP疯狂的访问,通过排查还是公司内部有安全部门的检测,但这种检测对于一些内部服务来说存在访问频率太高,造成内部的一些小机器服务根本扛不住的问题,所以这不,节流来了。

实现原理

既然都已经看源码了,那就总结一下drf不亏是非常有开发经验的人开发出来的,基本能想到的、想不到的都帮我们实现了。

自己实现版

import time
from rest_framework.throttling import BaseThrottle

VISIT_RECORD = {}


class VisitThrottle(BaseThrottle):

    def __init__(self):
        self.history = None

    def allow_request(self, request, view):
        # 1、获取IP,self.get_ident为BaseThrottle类提供的方法
        remote_addr = self.get_ident(request)
        # 2、保存
        ctime = time.time()
        if remote_addr not in VISIT_RECORD:
            VISIT_RECORD[remote_addr] = [ctime,]
            return True

        history = VISIT_RECORD.get(remote_addr)
        self.history = history
        while history and history[-1] < ctime - 60:
            history.pop()

        if len(history) < 3:
            history.insert(0, ctime)
            return True

    def wait(self):
        # 提示
        ctime = time.time()
        return 60 - (ctime - self.history[-1])

这个原理还是比较简单的,主要就是allow_requestwait2个方法的实现。

流程

通过看对应的源码,他的流程还是先从请求进来后走self.dispatch()self.initial()self.check_throttles()这个流程。(是在认证、权限判断之后)

配置及使用

这步还是比较简单的,直接在settings.py继续配置即可。

# 修改DRF认证
REST_FRAMEWORK = {
    ...
    # 节流配置
    "DEFAULT_THROTTLE_CLASSES": [
        'utils.throttle.VisitThrottle'
    ]
}

但是我们实际使用中,肯定不会用上面的自己实现版本来做,因为drf已经提供了一个更nb的方法给到我们可以简单使用。SimpleRateThrottle方法。由于实现的已经非常完善了,我们甚至只要几行代码就可以轻松实现。具体逻辑如上,实现也比较清晰。

# utils.throttle.VisitThrottle
class VisitThrottle(SimpleRateThrottle):
    scope = "endpein"

    def get_cache_key(self, request, view):
        # 需要实现告知以什么来作为唯一身份判断
        return self.get_ident(request)

# settings

REST_FRAMEWORK = {
    ...
    # 节流配置
    "DEFAULT_THROTTLE_CLASSES": [
        'utils.throttle.VisitThrottle'
    ],
    "DEFAULT_THROTTLE_RATES": {
        # 配置每分钟只能访问3次
        "endpein": '3/m'
    }

通过查看源码,支持的限流配置时间格式如下

{'s':1,'m':60,'h':3600,'d':86400}

同时可以针对登陆用户和非登陆用户进行不同的限制,所以在配置上会有所不同。但是非常简单了。

# utils.throttle.VisitThrottle
from rest_framework.throttling import BaseThrottle, SimpleRateThrottle

class VisitThrottle(SimpleRateThrottle):
    scope = "endpein"

    def get_cache_key(self, request, view):
        # 需要实现告知以什么来作为唯一身份判断
        return self.get_ident(request)
# 登陆用户
class UserThrottle(SimpleRateThrottle):
    scope = "endpeinUser"

    def get_cache_key(self, request, view):
        # 注意,这里有区别了,返回的是用户信息
        return request.user.username


# settings

REST_FRAMEWORK = {
    ...
    # 节流配置
    "DEFAULT_THROTTLE_CLASSES": [
        'utils.throttle.VisitThrottle',
    ],
    "DEFAULT_THROTTLE_RATES": {
        # 配置每分钟只能访问3次
        "endpein": '3/m',
        "endpeinUser":'10/m'
    }

注意,在上面代码,我并没有在DEFAULT_THROTTLE_CLASSES中增加UserThrottle类,而是对于非通用的,最简单的方式还是去对应的视图类下 增加throttle_classes = []这种方式来进行指定使用。