zoukankan      html  css  js  c++  java
  • DAY100

    一·、频率组件

    1.自定义频率简单使用

    # myThrottle.py
    
    import time
    class VisitThrottle():
        '''
            {'ip1':[时间1 ,时间2],
            'ip2':[时间1, ],
            }
        '''
        visit_dic = {}
        def __init__(self):
            self.history = None
            self.time = time.time
    
        def allow_request(self, request, view):
            # 取出访问者ip
            ip = request.META.get('REMOTE_ADDR')
            now_time = self.time()
            # 判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问
            if ip not in self.visit_dic:
                self.visit_dic[ip] = [now_time, ]
                return True
    
            # 用户不是第一次访问,直接到这里执行
            # 取出用户对应的列表
            self.history = self.visit_dic[ip]
    
            # 循环判断当前ip的列表,有值,并且列表的最后一个时间加上60s还是小于当前时间,把这种数据pop掉,这样列表中只有60s以内的访问时间
            while self.history and self.history[-1] + 60 < now_time:
                self.history.pop()
    
            # 判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过
            if len(self.history)<3:
                self.visit_dic[ip].insert(0,now_time)
                return True
            # 当大于等于3,说明一分钟内访问超过三次,返回False验证失败
            return False
    
        # 当访问被限制后,距离下次可以访问还剩的时间
        def wait(self):
            now_time = self.time()
            return 60 - (now_time - self.history[0])
    
    #views.py
    from django.shortcuts import render, HttpResponse
    from rest_framework.views import APIView
    from app01.myThrottle import VisitThrottle
    from rest_framework.exceptions import Throttled
    
    
    # Create your views here.
    
    class Book(APIView):
        # 局部使用
        throttle_classes = [VisitThrottle, ]
    
        def get(self, request):
            return HttpResponse('ok')
    	
        # 访问频率限制超出,错误信息(中文)
        def throttled(self, request, wait):
            # 自定义异常,并继承Throttled异常
            class MyThrottled(Throttled):
                default_detail = '距离下次访问'
                extra_detail_singular = '还有 {wait} second.'
                extra_detail_plural = '还有 {wait} seconds.'
    		# 抛出异常
            raise MyThrottled(wait)
         
    # 全局使用
    REST_FRAMEWORK = {
        'DEFAULT_THROTTLE_CLASSES': ['app01.myThrottle.VisitThrottle', ]
    }
    
    # 全局使用下局部禁用
    class Book(APIView):
        throttle_classes = []
    

    2.内置频率简单使用

    # settings.py
    REST_FRAMEWORK = {
        # 全局使用
        'DEFAULT_THROTTLE_CLASSES':['app01.myThrottle.VisitThrottle',],
        'DEFAULT_THROTTLE_RATES': {
            # time: 3次/每分钟
            'time': '3/m'
        }
    }
    
    # myThrottle.py
    from rest_framework.throttling import SimpleRateThrottle
    
    class VisitThrottle(SimpleRateThrottle):
        # 全局配置访问频率
        scope = 'time'
        # 局部配置访问频率
        # rate = '3/m'
        
        def get_cache_key(self, request, view):
            # 对什么的访问频率限制就返回什么
            # get_ident():SimpleRateThrottle的父类的方法,获得访问的IP
            return self.get_ident(request)#①
    
    # ①
    # get_ident()
    def get_ident(self, request):
        .....
        
        xff = request.META.get('HTTP_X_FORWARDED_FOR')
        # request.META.get('REMOTE_ADDR')
        # 从META里获得访问的IP地址
        remote_addr = request.META.get('REMOTE_ADDR')
        num_proxies = api_settings.NUM_PROXIES
    	.....
        
        return ''.join(xff.split()) if xff else remote_addr
    
    #views.py
    from django.shortcuts import render, HttpResponse
    from rest_framework.views import APIView
    from app01.myThrottle import VisitThrottle
    from rest_framework.exceptions import Throttled
    
    
    # Create your views here.
    
    class Book(APIView):
        # 局部使用
        throttle_classes = [VisitThrottle, ]
        # 局部禁用
        # throttle_classes = []
    
        def get(self, request):
            return HttpResponse('ok')
    	
        # 访问频率限制超出,错误信息(中文)
        def throttled(self, request, wait):
            # 自定义异常,并继承Throttled异常
            class MyThrottled(Throttled):
                default_detail = '距离下次访问'
                extra_detail_singular = '还有 {wait} second.'
                extra_detail_plural = '还有 {wait} seconds.'
    		# 抛出异常
            raise MyThrottled(wait)
    
    

    3.频率认证源码分析

    # 第一步
    # APIView类
    def dispatch(self, request, *args, **kwargs):
    	........
        # 重点是这个,这是认证、频率以及权限相关的
        self.initial(request, *args, **kwargs)
    	........
    
    # 第二步
    # APIView类
    def initial(self, request, *args, **kwargs):
    	........
        self.perform_authentication(request)
        self.check_permissions(request)
        # 频率
        self.check_throttles(request)
    
    # 第三步
    # APIView类
    def check_throttles(self, request):
    	for throttle in self.get_throttles():
            # throttle.allow_request的返回值是bool类型
            if not throttle.allow_request(request, self):
                # 如果返回False,触发self.throttled()的执行,抛出异常
                # throttle.wait():返回值是数值型,倒计时时间
               self.throttled(request, throttle.wait())
            
                
                
    # self.get_throttles()的来历
    def get_throttles(self):
        return [throttle() for throttle in self.throttle_classes]
    
    # self.throttled(request, throttle.wait())
    def throttled(self, request, wait):
        raise exceptions.Throttled(wait)
    

    4.内置频率控制类SimpleRateThrottle源码分析

    # 第一步
    # 从自定义的频率控制看出allow_request()是控制频率的主要代码
    class SimpleRateThrottle(BaseThrottle):
        ......
        timer = time.time
        ......
     	def allow_request(self, request, view):
            # 1.self.rate
    		 if self.rate is None:
                return True
            
    		# 2.get_cache_key 获得限制的对象
            self.key = self.get_cache_key(request, view)
            if self.key is None:
                return True
            
    		# self.cache.get(self.key, [])
            # 这个就相当于自定义频率控制中的大字典,是从缓存中获得
            # 如果self.cache中有对应self.key的列表,就赋值给self.history
            # 没有则创建并给默认值[]空列表
            self.history = self.cache.get(self.key, [])
            
            # timer = time.time
            # 加上()执行,获得当前的时间戳
            self.now = self.timer()
    		
            # 3.self.num_requests和self.duration
            # 循环判断,当前ip的列表有值,并且列表的当前时间减去self.duration小于最后一个时间,把这种数据pop掉,这样列表中只有self.duration以内的访问时间
            while self.history and self.history[-1] <= self.now - self.duration:
                self.history.pop()
            
            # 4.self.throttle_failure()和self.throttle_success()
            # 判断当列表大于self.num_requests,说明一分钟以内访问大于或等于self.num_requests次,执行self.throttle_failure()方法返回False验证失败
            if len(self.history) >= self.num_requests:
                return self.throttle_failure()
            
            # 当列表小于self.num_requests时,执行self.throttle_success()方法返回True
            return self.throttle_success()
    
    # 1.
    # self.rate
    class SimpleRateThrottle(BaseThrottle):
        .......
        # 全局属性
        THROTTLE_RATES = api_settings.DEFAULT_THROTTLE_RATES 
        .......
        def __init__(self):
            
            # 初始化时判断继承SimpleRateThrottle类的里面有没有rate,没有就执行self.get_rate()去找子类里scope
            if not getattr(self, 'rate', None):
                # self.rate = scope所代表的值
                self.rate = self.get_rate()
                
            self.num_requests, self.duration = self.parse_rate(self.rate)
    
        
    # self.get_rate
    	def get_rate(self):
        	# 如果没有scope就会报错
         	if not getattr(self, 'scope', None):
            	msg = ("You must set either `.scope` or `.rate` for '%s' throttle" %self.__class__.__name__)
            	raise ImproperlyConfigured(msg)
    		# 如果有的话就去self的THROTTLE_RATES里找,也就是去setting里的DEFAULT_THROTTLE_RATES中找scope值对应的
         	try:
            	return self.THROTTLE_RATES[self.scope]
         	except KeyError:
            	msg = "No default throttle rate set for '%s' scope" % self.scope
            	raise ImproperlyConfigured(msg)
    
    # 2.
    # self.get_cache_key
    class SimpleRateThrottle(BaseThrottle):
    # 如果继承SimpleRateThrottle类的里面不写,就会抛出异常,所以必须写
        def get_cache_key(self, request, view):
            raise NotImplementedError('.get_cache_key() must be overridden')
    
    
    # 3.
    # self.num_requests和self.duration
    class SimpleRateThrottle(BaseThrottle):
        .......
        # 全局属性
        THROTTLE_RATES = api_settings.DEFAULT_THROTTLE_RATES 
        .......
        def __init__(self):
            if not getattr(self, 'rate', None):
                # self.rate = scope所代表的值,比如‘3/m’
                self.rate = self.get_rate()
            # 把self.rate当作参数给self.parse_rate(),并且把返回值解压分给了self.num_requests和self.duration
            self.num_requests, self.duration = self.parse_rate(self.rate)
            
            
    # self.parse_rate
     	def parse_rate(self, rate):
            if rate is None:
                return (None, None)
            # 假设rate = ‘3/m’
            # num = '3',period = 'm'
            num, period = rate.split('/')
            # num_requests = 3 
            num_requests = int(num)
            # duration = 60
            duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]
            # return(3,60) 表示3次/60秒
            return (num_requests, duration)
    
    #4
    # self.throttle_failure()和self.throttle_success()
    class SimpleRateThrottle(BaseThrottle):
        def throttle_success(self):
            # 把当前访问时间插入self.history的第一个
            self.history.insert(0, self.now)
            # 并且存入缓存中
            self.cache.set(self.key, self.history, self.duration)
            return True
    
        def throttle_failure(self):
            # 直接返回False
            return False
    

    二、解释器

    根据请求头 content-type 选择对应的解析器对请求体内容进行处理。

    有application/json,x-www-form-urlencoded,form-data等格式

    1.简单使用

    from rest_framework.parsers import FileUploadParser, MultiPartParser, JSONParser, FormParser
    
    # 局部全部使用
    # 视图里
        parser_classes = [FileUploadParser, MultiPartParser, JSONParser, FormParser]
        
    # 局部单个使用,只使用指定的解释器解释
    # 视图里
        parser_classes = [FileUploadParser,]
        
    # 全局使用
    # setting.py
    REST_FRAMEWORK = {
        'DEFAULT_PARSER_CLASSES':[
            'rest_framework.parsers.JSONParser'
            'rest_framework.parsers.FormParser'
            'rest_framework.parsers.MultiPartParser'
        ]
    
    }
    

    2.源码解析

    # 在调用request.data时,才进行解析,由此入手
    # request
        @property
        def data(self):
            if not _hasattr(self, '_full_data'):
                self._load_data_and_files()
            return self._full_data
    
    # request
    #  self._load_data_and_files()
    def _load_data_and_files(self):
        if not _hasattr(self, '_data'):
            # self._parse() 解析之后 把解析的分到data和files里
            self._data, self._files = self._parse()
        .......   
    
    # request
    # self._parse()
    def _parse(self):
        # media_type = 用户请求头里content_type的值
        media_type = self.content_type
    
        
        #self里就有content_type,传入此函数
        parser = self.negotiator.select_parser(self, self.parsers)
        
        
    # self.content_type 
    def content_type(self):
            meta = self._request.META
            return meta.get('CONTENT_TYPE', meta.get('HTTP_CONTENT_TYPE', ''))
        
    # self.parsers
    # self.parsers Request对象实例化时传进来的参数self.get_parsers()
    def initialize_request(self, request, *args, **kwargs):
        
        parser_context = self.get_parser_context(request)
        return Request(
            request,
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )
    
    # self.get_parsers()
    def get_parsers(self):
        # 先从类本身找,找不到去父类找即APIVIew 中的
        return [parser() for parser in self.parser_classes]
    
    # self.negotiator.select_parser(self, self.parsers)
    def select_parser(self, request, parsers):
        # parsers:parser_classes,也就是解析器列表
        # 循环解析器列表
        for parser in parsers:
            # parser.media_type:解析器所能解析的类型
            # request.content_type:请求中的解析方式
            # 如果一致返回解析器,否则返回None
            if media_type_matches(parser.media_type, request.content_type):
                return parser
        return None
    
  • 相关阅读:
    关于SQLite
    Solr开发文档
    Using Fiddler with IIS
    SQL SERVER – Difference Between Union vs. Union All – Optimal Performance Comparison
    Git资料
    VS2010版快捷键
    IE9子iframe父iframe cookie设置诡异问题
    美国的企业家宣言
    互联网程序编写原则
    分析牛人js版删除代码注释(状态机机制)
  • 原文地址:https://www.cnblogs.com/xvchengqi/p/10121454.html
Copyright © 2011-2022 走看看