07 drf source code analysis of the throttle

07 drf source code analysis of the throttle

1. Description of the throttle

  • Throttling similar to the authority, which determines whether the request should be authorized. Throttle provisional indication state, and for controlling the rate request may be issued to a client API.

  • There may be the case for some services, especially resource-intensive, so you need to apply different constraints in different parts of the API.

  • Frequency limit after authentication, permissions

2. throttle use

  • Settings can be accessed period specified in the configuration settings file number

    REST_FRAMEWORK = {
        "DEFAULT_THROTTLE_RATES": {"anon": '10/m'},
    }
  • In addition throttle_classes required throttle class

    from rest_framework.views import APIView
    from rest_framework.response import Response
    
    from rest_framework.throttling import AnonRateThrottle,BaseThrottle
    
    class ArticleView(APIView):
        throttle_classes = [AnonRateThrottle,]
        def get(self,request,*args,**kwargs):
            return Response('文章列表')
    
    class ArticleDetailView(APIView):
        def get(self,request,*args,**kwargs):
            return Response('文章列表')

3. source code analysis

  • Dispatch request came first execution method

    class APIView(View):
        permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
    
        def dispatch(self, request, *args, **kwargs):
            # 封装request对象...
            self.initial(request, *args, **kwargs)
            # 通过反射执行视图中的方法...
  • initial transition method

    def initial(self, request, *args, **kwargs):
        # 版本的处理...
        # 认证...       
        # 权限判断
    
        self.check_throttles(request) # 节流
  • The throttle all class instances into the object list

    def get_throttles(self):
        return [throttle() for throttle in self.throttle_classes]
  • Loop execution method of each object allow_request

    def check_throttles(self, request):
        throttle_durations = []
        for throttle in self.get_throttles():
            if not throttle.allow_request(request, self):
                throttle_durations.append(throttle.wait())
  • Allow_request execution method, AnonRateThrottle no allow_request, go looking for parent

    class AnonRateThrottle(SimpleRateThrottle):
        scope = 'anon'
    
        def get_cache_key(self, request, view):
            if request.user.is_authenticated:
                return None  # Only throttle unauthenticated requests.
    
            return self.cache_format % {
                'scope': self.scope,
                'ident': self.get_ident(request)
            }
  • Method performed SimpleRateThrottle class allow_request

    • Request for obtaining the user's IP
    • According to IP get access to all of his records
    • Get the current time
    • The recording time is not specified deleted
    • Within a period of time to determine how many access
    • And set the number of comparison to determine whether the user can continue to access
    class SimpleRateThrottle(BaseThrottle):
        cache = default_cache
        timer = time.time
        cache_format = 'throttle_%(scope)s_%(ident)s'
        scope = None
        THROTTLE_RATES = api_settings.DEFAULT_THROTTLE_RATES
    
        def __init__(self):
            if not getattr(self, 'rate', None):
                self.rate = self.get_rate()
            self.num_requests, self.duration = self.parse_rate(self.rate)
    
        def parse_rate(self, rate):
            if rate is None:
                return (None, None)
            num, period = rate.split('/')
            num_requests = int(num)
            duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]
            return (num_requests, duration)
    
        def allow_request(self, request, view):
            if self.rate is None:  
                return True
    
            # 获取请求用户的IP
            self.key = self.get_cache_key(request, view)
            if self.key is None:
                return True
    
            # 根据IP获取他的所有访问记录,[]
            self.history = self.cache.get(self.key, [])
    
            self.now = self.timer()
    
            while self.history and self.history[-1] <= self.now - self.duration:
                self.history.pop()
            if len(self.history) >= self.num_requests:
                return self.throttle_failure()
            return self.throttle_success()
    
        def throttle_success(self):
            self.history.insert(0, self.now)
            self.cache.set(self.key, self.history, self.duration)
            return True
    
        def throttle_failure(self):
            return False
    
        def wait(self):
            if self.history:
                remaining_duration = self.duration - (self.now - self.history[-1])
            else:
                remaining_duration = self.duration
    
            available_requests = self.num_requests - len(self.history) + 1
            if available_requests <= 0:
                return None
    
            return remaining_duration / float(available_requests)

to sum up:

  • The principle
    When to visit:
    1. Get the current time 100 121 280
    2.100121280-60 = 100,121,220, delete all records of less than 100 121 220
    3. judge within 1 minute, you have visited many times? 4
    4. inaccessible
    to stop for a
    while to visit:
    1. Get the current time 100 121 340
    2.100121340-60 = 100,121,280, delete all records of less than 100 121 280
    3. judge within 1 minute, you have visited many times? 0
    4. You can access
  • specific process
    1. When the method is executed allow_follow request,
    2. Ip access request of the user will use self.key, and then recorded self.history obtain access to user's ip,
    3. Get the current time, minus the set period of time with the current time,
    4. Recording the user access cycle, recording will not pop out of the time period,
    5. Len is determined by the time period has been visited many times over limit the number of false returns
    6. Anonymous users to restrict access by ip, login user to restrict access by user id

Guess you like

Origin www.cnblogs.com/liubing8/p/11941224.html