yyz notes yyz notes
首页
  • RBAC权限设计
  • 架构图标设计
  • 账号体系
  • python基础
  • python高级
  • python模块
  • python设计模式
  • python数据结构与算法
  • django
  • django-DRF
  • flask
  • 直接设计开源pip包
  • 直接设计开源项目
  • python示例题/脚本
  • python面试题
  • golang基础
  • golang高级
  • golang常用组件
  • gin框架
  • es6
  • javascript
  • react
  • vue
  • TypeScript
  • mysql
  • redis
  • minio
  • elasticsearch
  • mongodb
  • 消息队列
  • 自动化测试
  • 操作系统

    • linux
    • windows
  • nginx
  • docker
  • k8s
  • git
  • ldap
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

益章

可乐鸡翅
首页
  • RBAC权限设计
  • 架构图标设计
  • 账号体系
  • python基础
  • python高级
  • python模块
  • python设计模式
  • python数据结构与算法
  • django
  • django-DRF
  • flask
  • 直接设计开源pip包
  • 直接设计开源项目
  • python示例题/脚本
  • python面试题
  • golang基础
  • golang高级
  • golang常用组件
  • gin框架
  • es6
  • javascript
  • react
  • vue
  • TypeScript
  • mysql
  • redis
  • minio
  • elasticsearch
  • mongodb
  • 消息队列
  • 自动化测试
  • 操作系统

    • linux
    • windows
  • nginx
  • docker
  • k8s
  • git
  • ldap
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • python基础

  • python高级

  • python模块

  • python设计模式

  • python数据结构与算法

  • django

  • django-DRF

    • win环境快速搭建drf项目
    • DRF介绍及快速使用
    • 序列化
    • DRF请求和响应
    • DRF类视图
    • 认证
    • 权限
    • 接口访问控制(限流)
      • 链接资料
      • 1. 限流介绍
      • 2. SimpleRateThrottle 源码分析
        • 2.1 导入 SimpleRateThrottle
        • 2.2 查看源码
        • 2.3 自定义限流
        • 自己写的方式使用(基本使用)
      • 3. 自定义限制频率(节流)
        • 3.1 新建内置频率类
        • 3.2 全局配置
        • 3.3 局部配置
    • 版本
    • 分页
    • 解析器
    • 自定义异常格式
    • 自定义响应格式
    • 过滤
    • 搜索
    • 排序
  • flask

  • 自己设计开源pip包

  • 自己设计开源项目

  • python小示例

  • python面试题

  • python
  • django-DRF
YiZhang-You
2023-05-20
目录

接口访问控制(限流)

# 链接资料

  1. drf官方文档

    Home - Django REST framework (opens new window)

  2. drf官方源码地址

    GitHub - encode/django-rest-framework: Web APIs for Django. 🎸 (opens new window)

  3. 博客园

    7-1 频率-DRF限制频率 (opens new window)

# 1. 限流介绍

 开放平台的API接口调用需要限制其频率,以节约服务器资源和避免恶意的频繁调用。其实有的时候我们辛辛苦苦造的数据被爬虫份子给爬掉。爬虫在爬数据的时候数据量也比较大,那么这个时候就会给我们服务器造成了压力,影响用户的使用。在这个时候我们就要限制用户的使用频率。那怎么限制呐?我们给出一些限制的思路:
1
 节流思路:

    我现在想 限制 每个用户  1分钟之内 只能访问 3次(3/min),并且每个用户在访问的时候,我按一定的规则记录当前用户访问的记录,比如我按 ip地址记录:

    {"127.0.0.1": {"12:29:50","12:29:40","12:29:20'"}}:指的是 我 127.0.0.1 ip地址在1分钟之内访问 3次。这个时候我在  12:30:10 去访问时,在1分钟之内,很明显无法访问。

    那我如果是 12:30:21 去访问,这个时候 12:30:21 跟 {"127.0.0.1": {"12:29:50","12:29:40","12:29:20'"}} 中最后一个值 12:29:20 比,大于1分钟了,这个时候可以访问了。

         那个这个时候 列表就变成:  {"127.0.0.1": {"12:30:21","12:29:50","12:29:40"}} 就把 12:30:21 加到列表中第一个参数,把 12:29:20列表中删除掉。

    依次类推...
1
2
3
4
5
6
7
8
9
10
11

# 2. SimpleRateThrottle 源码分析

# 2.1 导入 SimpleRateThrottle

from rest_framework.throttling import SimpleRateThrottle
1

# 2.2 查看源码

Ctrl + SimpleRateThrottle -> BaseThrottle
1

发现它是继承一个基础类 Ctrl + BaseThrottle ,有哪些东西:

class BaseThrottle(object):
    """
    Rate throttling of requests.
    """
 
    def allow_request(self, request, view):  #必须要实现的1个方法,True:允许访问  False:禁止访问
        """
        Return `True` if the request should be allowed, `False` otherwise.
        """
        raise NotImplementedError('.allow_request() must be overridden')
 
    def get_ident(self, request):
        .....
 
    def wait(self):
        .....
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
还是先dispatch 和上面一样

  def initial(self, request, *args, **kwargs):
        """
        Runs anything that needs to occur prior to calling the method handler.
        """
        self.format_kwarg = self.get_format_suffix(**kwargs)

        # Perform content negotiation and store the accepted info on the request
        neg = self.perform_content_negotiation(request)
        request.accepted_renderer, request.accepted_media_type = neg

        # Determine the API version, if versioning is in use.
        version, scheme = self.determine_version(request, *args, **kwargs)
        request.version, request.versioning_scheme = version, scheme

        # Ensure that the incoming request is permitted
        # 实现认证
        self.perform_authentication(request)
        # 权限判断
        self.check_permissions(request)
        # 限流
        self.check_throttles(request)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def check_throttles(self, request):
        """
        Check if request should be throttled.
        Raises an appropriate exception if the request is throttled.
        """
        throttle_durations = []
        for throttle in self.get_throttles():  # 获取列表
            if not throttle.allow_request(request, self):
                throttle_durations.append(throttle.wait())

        if throttle_durations:
            # Filter out `None` values which may happen in case of config / rate
            # changes, see #1438
            durations = [
                duration for duration in throttle_durations
                if duration is not None
            ]

            duration = max(durations, default=None)
            self.throttled(request, duration)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 2.3 自定义限流

# 自己写的方式使用(基本使用)

通过IP的方式自定义

# 重写限流类

class hisitThrottle(BaseThrottle):
    """60秒只能访问3次"""

    def __init__(self):
        self.history = None

    def allow_request(self, request, view):
        """返回True表示可以访问"""
        remote_addr = request.META.get('REMOTE_ADDR')  # 获取当前用户的IP
        ctime = time.time()
        if remote_addr not in VISIT_RECORD:
            VISIT_RECORD[remote_addr] = [ctime, ]  # 注意这里是以列表形式添加
        history = VISIT_RECORD.get(remote_addr)  # 获取时间戳[]
        self.history = history
        print(self.history)
        while history and history[-1] < ctime - 60:  # 如果最后一个时间戳小于当前时间戳-60秒(就为True),
            history.pop()
        if len(history) < 3:  # 只让访问3次
            history.insert(0, ctime)  # 把当前时间添加到第一个
            return True

    def wait(self):
        """还需要等待多少秒才可以执行"""
        ctime = time.time()

        return 60 - (ctime - self.history[0])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 使用
class AuthLoginView(APIView):
    """用户登录"""
    authentication_classes = []
    permission_classes = []
    throttle_classes = [hisitThrottle]  # 使用

    def post(self, request, *args, **kwargs):
        ret = {'code': 1000, 'message': 'ok!'}
        try:
            username = request._request.POST.get('username')  # 获取前端传递过来的内容
            password = request._request.POST.get('password')
            obj = models.UserInfo.objects.filter(username=username, password=password).first()
            if not obj:
                ret['code'] = 1002
                ret['message'] = "用户密码错误"
            # 成功后为登录用户生产token
            token = md5(username)
            models.UserToken.objects.update_or_create(user=obj, defaults={'token': token})
            ret['token'] = token
        except Exception as e:
            ret['code'] = 1003
            ret['message'] = "请求异常"
        return JsonResponse(ret)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 3. 自定义限制频率(节流)

# 3.1 新建内置频率类

说明:在应用下新建一个throttlings文件。创建频率类:

from rest_framework.throttling import SimpleRateThrottle
 
 
class VisitThrottle(SimpleRateThrottle):
    scope = "未认证用户"
   
    def get_cache_key(self, request, view):
        return  self.get_ident(request)   #ip地址当做key,可以会缓存到django的缓存里面
         
  
class UserThrottle(SimpleRateThrottle):
    scope = "已认证用户"
   
    def get_cache_key(self, request, view):  #要写一个认证方法,告诉人家你拿什么当key
        return  request.user  #当前登录用户当做key
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

好了,频率类 新建好了。

# 3.2 全局配置

说明:在settings.py的REST_FRAMEWORK 下配置全局。

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': ....,
    'DEFAULT_PERMISSION_CLASSES': ...,
    'DEFAULT_THROTTLE_CLASSES': ['app05.throttlings.UserThrottle', ],
    'DEFAULT_THROTTLE_RATES': {
        '未认证用户': '3/m',
        '已认证用户': '10/m',
    },
}
1
2
3
4
5
6
7
8
9

意思是:未认证用户 1分钟3次,认证用户是 1分钟10次。那这个时间定义在哪里定义的呐?SimpleRateThrottle源码中有,我们来看看:

class SimpleRateThrottle(BaseThrottle):
    """
    ...
    Period should be one of: ('s', 'sec', 'm', 'min', 'h', 'hour', 'd', 'day')  #时间设置
    ....
    """
    ....
1
2
3
4
5
6
7

# 3.3 局部配置

说明:上面是全局配置,但是有的时候我不想全局的,我只想局部实现,那咋办呐?

from .throttlings import VisitThrottle  #导入自定义频率类
 
# Create your views here.
 
 
class CartView(APIView):
 
    # 节流 局部配置
    throttle_classes = [VisitThrottle]
 
    def get(self, request, *args, **kwargs):
 
        ....
        return JsonResponse(ctx)
1
2
3
4
5
6
7
8
9
10
11
12
13
14

但是全局也写了,我只想在视图中什么限制也不想加,那我们可以是  throttle_classes 为空就行了,如下:

class CartView(APIView):
 
    # 视图不加任何限制,但是全局已经配置了
    throttle_classes = []
 
    ...
1
2
3
4
5
6
编辑 (opens new window)
权限
版本

← 权限 版本→

最近更新
01
配置yun源
05-24
02
linux-配置python虚拟环境
05-24
03
linux文件目录管理
05-24
更多文章>
Theme by Vdoing | Copyright © 2023-2023 yizhang | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式