table of Contents
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
- When the method is executed allow_follow request,
- Ip access request of the user will use self.key, and then recorded self.history obtain access to user's ip,
- Get the current time, minus the set period of time with the current time,
- Recording the user access cycle, recording will not pop out of the time period,
- Len is determined by the time period has been visited many times over limit the number of false returns
- Anonymous users to restrict access by ip, login user to restrict access by user id