前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python_restframework

python_restframework

作者头像
py3study
发布2020-01-15 11:25:38
3640
发布2020-01-15 11:25:38
举报
文章被收录于专栏:python3python3

BaseThrottle

代码语言:javascript
复制
(1) 取出访问者ip
(2) 判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问,在字典里,继续往下走
(3) 循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
(4) 判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过
(5) 当大于等于3,说明一分钟内访问超过三次,返回False验证失败

1、分发display

代码语言:javascript
复制
def dispatch(self, request, *args, **kwargs):
    try:
        # 进入初始化
        self.initial(request, *args, **kwargs)

2、 drf初始化方法

代码语言:javascript
复制
APIview下的方法
def initial(self, request, *args, **kwargs):
    # 认证
    self.perform_authentication(request)
    # 进入权限
    self.check_permissions(request)
    # --> 频率
    self.check_throttles(request)

3、频率模块

代码语言:javascript
复制
def check_throttles(self, request):
    """
    Check if request should be throttled.
    Raises an appropriate exception if the request is throttled.
    """
    # 循环的是列表
    for throttle in self.get_throttles():
        # 返回结果true or false, false就继续执行
        if not throttle.allow_request(request, self):
            # 视图类的三个参数, self, request,  
            # throttle.wait(): 最后wait返回的数字
            self.throttled(request, throttle.wait())

3.1、for throttle in self.get_throttles():

代码语言:javascript
复制
def get_throttles(self):
    """
    Instantiates and returns the list of throttles that this view uses.
    """
    # 跟权限组件一样, 这里循环 return出去的也是一个列表
    return [throttle() for throttle in self.throttle_classes]

3.2、if 判断

代码语言:javascript
复制
# 当返回为false时,说明该用户或订单无此权限,   
# not false为true 继续往下执行, not true就是 false, 不执行下面代码
if not throttle.allow_request(request, self):

3.3、throttle.allow_request

代码语言:javascript
复制
# 如果是false 就直接返回这个错误了
def allow_request(self, request, view):
    """
    Return `True` if the request should be allowed, `False` otherwise.
    """
    raise NotImplementedError('.allow_request() must be overridden')

4、BasePermission

代码语言:javascript
复制
# 继承基础的认证权限, 如果忘了要定义哪个类 直接在这里看也OK

from rest_framework.throttling import BaseThrottle
    # 自定义的组件
    def allow_request(self, request, view):
        raise NotImplementedError('.allow_request() must be overridden')

    def get_ident(self, request):
        xff = request.META.get('HTTP_X_FORWARDED_FOR')
        remote_addr = request.META.get('REMOTE_ADDR')
        num_proxies = api_settings.NUM_PROXIES

        if num_proxies is not None:
            if num_proxies == 0 or xff is None:
                return remote_addr
            addrs = xff.split(',')
            client_addr = addrs[-min(num_proxies, len(addrs))]
            return client_addr.strip()

        return ''.join(xff.split()) if xff else remote_addr
    # 最后要返回的时间或者其它
    def wait(self):
        return None

5、定义一个权限

代码语言:javascript
复制
class MyPermission(BasePermission):
    # 前台返回的错误
    message = "您没有权限, 请先联系下管理员增加权限"
    # 获取权限
    def has_permission(self,request, view):
        # 认证组件, 返回的request.user
        print("permission: ", request.user.permission)
        if request.user.permission > 1:
            # 如果大于就是true, 在第3步,if not true 等于false就不执行它了
            return True
        return False

6、频率组件

代码语言:javascript
复制
class FirstThrottle(BaseThrottle):
    get_ip = {}

    def __init__(self):
        self.history = None
        self.ip = None
        self.ctime = time.time()

    def allow_request(self, request, view):
        :param request: 浏览器请求过来的数据
        :param view: apiview视图
        :return: true or false

        # 1、取出访问者的IP
        client_ip = request.META.get("REMOTE_ADDR")
        self.ip = client_ip
        # 2、判断不存在的话添加到字典 并将时间也一并添加进去
        if client_ip not in self.get_ip:
            self.get_ip[client_ip] = [self.ctime, ]
            return True
        # 获取当前IP的访问时间记录
        self.history = self.get_ip[client_ip]

        # 3、 开始循环判断, 如果最后一个大于60秒就直接干掉
        while self.history and self.ctime - self.history[-1] > 60:
            self.history.pop()

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

    def wait(self):
        last_time = self.ctime - self.history[-1] - 10
        if last_time == 0:
            self.get_ip[self.ip].clear()
        return last_time

7、全局使用频率

代码语言:javascript
复制
# settings.py文件中定义, 所有的组件都可以放在这里

REST_FRAMEWORK = {
    "DEFAULT_THROTTLE_CLASSES": [
        'app01.myauth.FirstThrottle',  # 全局使用权限
    ]
}

7、局部使用

代码语言:javascript
复制
类中直接使用 
    throttle_classes = [FirstThrottle, ]

8、局部禁用

代码语言:javascript
复制
类中直接使用 
    throttle_classes = []

SimpleRateThrottle

使用组件中自带的频率控制组件 先在settings.py中定义限制频率的范围 REST_FRAMEWORK={ "DEFAULT_THROTTLE_RATES": { "thro_rate": "10/m" } }

1、进入频率

代码语言:javascript
复制
class SimpleRateThrottle(BaseThrottle):
    cache = default_cache
    # 获取时间
    timer = time.time
    cache_format = 'throttle_%(scope)s_%(ident)s'
    # 这个是在setting中设置的 DEFAULT_THROTTLE_RATES的字典key, 必须得定义
    scope = None
    THROTTLE_RATES = api_settings.DEFAULT_THROTTLE_RATES

    # 初始化,
    def __init__(self):
        # 首先就是先判断 rate是否为空, 如果是false为空,就进入self.get_rate 
        if not getattr(self, 'rate', None):
            # 直接输出错误
            self.rate = self.get_rate()
        # 如果上一步通过,就继续进入这里 9.2    
        self.num_requests, self.duration = self.parse_rate(self.rate)
        # 也就是说执行完9.2之后 获取到的结果就是
        # self.num_requests, self.duration = (10,60)

1.1、get_rate

代码语言:javascript
复制
def get_rate(self):
    # scope 这个值在类中必须被定义成 settings中定义的值 如thro_rate
    if not getattr(self, 'scope', None):
        msg = ("You must set either `.scope` or `.rate` for '%s' throttle" %
        self.__class__.__name__)
        raise ImproperlyConfigured(msg)
    try:
        # 在配置文件中 将thro_rate 取出, 返回 10/m
        return self.THROTTLE_RATES[self.scope]
    except KeyError:
        msg = "No default throttle rate set for '%s' scope" % self.scope
        raise ImproperlyConfigured(msg)

2、当初始化通过

​ self.num_requests, self.duration = self.parse_rate(self.rate)

代码语言:javascript
复制
def parse_rate(self, rate):
    """
    Given the request rate string, return a two tuple of:
    <allowed number of requests>, <period of time in seconds>
    """
    # 这个是在setting中设置的 DEFAULT_THROTTLE_RATES的字典设置为空,就直接返回none,none
    if rate is None:
        return (None, None)
    # 这里的rate就是就是get_rate取出来的10/m 然后切割它
    num, period = rate.split('/')
    num_requests = int(num)
    # 定义如果是m就是60秒,然后字典中直接取值这里是m取出来的就是60
    duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]
    # 最后返回它俩
    return (num_requests, duration)

3、类中调用get_cache_key

代码语言:javascript
复制
def get_cache_key(self, request, view):
    """
    # 应返回可用于限制的唯一缓存键。
    Should return a unique cache-key which can be used for throttling.
    # 必须要重写, 否则调用SimpleRateThrottle也会直接报错
    Must be overridden.

    May return `None` if the request should not be throttled.
    """
    raise NotImplementedError('.get_cache_key() must be overridden')

4、实例

代码语言:javascript
复制
class FirstThrottle(SimpleRateThrottle):
    # 这里会调用 self.get_rate那个函数,返回的就是 10/m了
    scope = "thro_rate"

    # 如果不重新定义就会报错, 因为它得从缓存中找出 ip地址
    def get_cache_key(self, request, view):
        # 返回空也行, 也会有倒计时
        return self.get_ident(request)
        # "detail": "Request was throttled. Expected available in 56 seconds."

5、中文显示错误日志

5.1、流程的前3步

代码语言:javascript
复制
def check_throttles(self, request):
    """
    Check if request should be throttled.
    Raises an appropriate exception if the request is throttled.
    """
    for throttle in self.get_throttles():
        if not throttle.allow_request(request, self):
            # 如果不存在 就进入到 throttled中
            self.throttled(request, throttle.wait())

5.2、throttled 错误提示

代码语言:javascript
复制
def throttled(self, request, wait):
    """
    If request is throttled, determine what kind of exception to raise.
    """
    # 返回错误信息
    raise exceptions.Throttled(wait)

5.3、重写exceptions方法

代码语言:javascript
复制
class Throttled(APIException):
    status_code = status.HTTP_429_TOO_MANY_REQUESTS
    default_detail = _('Request was throttled.')
    extra_detail_singular = 'Expected available in {wait} second.'
    extra_detail_plural = 'Expected available in {wait} seconds.'

5.4、实例

代码语言:javascript
复制
from app01.SelfThrottle import FirstThrottle
from rest_framework import exceptions

class Thor(APIView):
    # 局部使用
    throttle_classes = [FirstThrottle, ]

    def get(self, request, *args, **kwargs):
        return HttpResponse("ok")

    # 需要注意的是 这里需要在视图类的重写方法,或继承
    def throttled(self, request, wait):
        class Myerrors(exceptions.Throttled):
            default_detail = "超出频率限制"
            extra_detail_singular = '请 {wait} 秒后在访问.'
            extra_detail_plural = '请 {wait} 秒后在访问.'

        raise Myerrors(wait)
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-06-28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • BaseThrottle
    • 1、分发display
      • 2、 drf初始化方法
        • 3、频率模块
          • 3.1、for throttle in self.get_throttles():
          • 3.2、if 判断
          • 3.3、throttle.allow_request
        • 4、BasePermission
          • 5、定义一个权限
            • 6、频率组件
              • 7、全局使用频率
                • 7、局部使用
                  • 8、局部禁用
                  • SimpleRateThrottle
                    • 1、进入频率
                      • 1.1、get_rate
                    • 2、当初始化通过
                      • 3、类中调用get_cache_key
                        • 4、实例
                          • 5、中文显示错误日志
                            • 5.1、流程的前3步
                            • 5.2、throttled 错误提示
                            • 5.3、重写exceptions方法
                            • 5.4、实例
                        领券
                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档