Python? Restframework (frequency component)

BaseThrottle (1) take out the visitor ip (2) judge that the current ip is not in the ACCESS Dictionary, add it in, and return True directly, indicati...
1. Distribute display
2. drf initialization method
3. Frequency module
4,BasePermission
5. Define a permission
6. Frequency components
7. Global usage frequency
7. Local use
8. Local prohibition
1. Access frequency
2. When initialization passes
3. Call get_cache_key in class
4. Example
5. Error log in Chinese
BaseThrottle (1) take out the visitor ip (2) judge that the current ip is not in the ACCESS Dictionary, add it in, and return True directly, indicating the first access, and continue to go down in the dictionary (3) circularly judge the list of current ip, which has a value, and the last time of subtracting the list from the current time is greater than 60s, pop this kind of data, so that there is only access time within 60s in the list, (4) judge that when the list is less than 3, it means less than three accesses in one minute, insert the current time to the first position of the list, return True, and pass successfully (5) if it is greater than or equal to 3, it means that it has been accessed more than three times in a minute, and False verification failure is returned

1. Distribute display

def dispatch(self, request, *args, **kwargs): try: # Enter initialization self.initial(request, *args, **kwargs)

2. drf initialization method

APIview Next method def initial(self, request, *args, **kwargs): # Authentication self.perform_authentication(request) # Access authority self.check_permissions(request) # > frequency self.check_throttles(request)

3. Frequency module

def check_throttles(self, request): """ Check if request should be throttled. Raises an appropriate exception if the request is throttled. """ # The loop is a list for throttle in self.get_throttles(): # Return the result true or false, false to continue execution if not throttle.allow_request(request, self): # Three parameters of view class, self, request, # throttle.wait(): the number returned by the last wait self.throttled(request, throttle.wait())

3.1,for throttle in self.get_throttles():

def get_throttles(self): """ Instantiates and returns the list of throttles that this view uses. """ # Just like the permission component, the circular return is also a list return [throttle() for throttle in self.throttle_classes]

3.2 if judgment

# When false is returned, the user or order does not have this permission, # If not false is true, continue to execute. If not true is false, do not execute the following code if not throttle.allow_request(request, self):

3.3,throttle.allow_request

# If it is false, it will directly return this error 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

# Inherit the basic authentication permission. If you forget which class you want to define, it's OK to see it here from rest_framework.throttling import BaseThrottle # Custom components 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 # Last time to return or other def wait(self): return None

5. Define a permission

class MyPermission(BasePermission): # Error returned by foreground message = "You do not have permission, Please contact the administrator first to add permissions" # Get permission def has_permission(self,request, view): # Authentication component, returned request.user print("permission: ", request.user.permission) if request.user.permission > 1: # If greater than is true, in step 3, if not true is equal to false, it will not be executed return True return False

6. Frequency components

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: Data requested by browser :param view: apiview view :return: true or false # 1. Retrieve the IP address of the visitor client_ip = request.META.get("REMOTE_ADDR") self.ip = client_ip # 2. Add the word that does not exist to the dictionary and add the time together if client_ip not in self.get_ip: self.get_ip[client_ip] = [self.ctime, ] return True # Get access time record of current IP self.history = self.get_ip[client_ip] # 3. Start circular judgment. If the last one is longer than 60 seconds, it will be killed directly 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. Global usage frequency

# Defined in settings.py file, all components can be put here REST_FRAMEWORK = { "DEFAULT_THROTTLE_CLASSES": [ 'app01.myauth.FirstThrottle', # Global access ] }

7. Local use

Class throttle_classes = [FirstThrottle, ]

8. Local prohibition

Class throttle_classes = [] SimpleRateThrottle

Use the frequency control component in the component

First define the range of limiting frequency in settings.py REST_FRAMEWORK={ "DEFAULT_THROTTLE_RATES": { "thro_rate": "10/m" } }

1. Access frequency

class SimpleRateThrottle(BaseThrottle): cache = default_cache # Acquisition time timer = time.time cache_format = 'throttle_%(scope)s_%(ident)s' # This is the dictionary key of the default? Thread? Rates set in setting. It must be defined scope = None THROTTLE_RATES = api_settings.DEFAULT_THROTTLE_RATES # Initialization, def __init__(self): # First of all, judge whether rate is empty. If false is empty, enter self.get \ if not getattr(self, 'rate', None): # Direct output error self.rate = self.get_rate() # If you passed the previous step, continue to 9.2 self.num_requests, self.duration = self.parse_rate(self.rate) # That is to say, the result obtained after 9.2 is # self.num_requests, self.duration = (10,60)

1.1,get_rate

def get_rate(self): # scope must be defined as the value defined in settings, such as 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: # Take thro rate out of the configuration file and return 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. When initialization passes

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

def parse_rate(self, rate): """ Given the request rate string, return a two tuple of: <allowed number of requests>, <period of time in seconds> """ # This is set in setting. If the dictionary of default? Throttle? Rates is set to null, it will directly return none,none if rate is None: return (None, None) # The rate here is the 10/m taken out by get rate and then cut it. num, period = rate.split('/') num_requests = int(num) # If it's m, it's 60 seconds. Then it's a direct value in the dictionary. If it's m, it's 60 seconds duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]] # Finally, return to them return (num_requests, duration)

3. Call get_cache_key in class

def get_cache_key(self, request, view): """ # A unique cache key that can be used for throttling should be returned. Should return a unique cache-key which can be used for throttling. # Must be overridden, otherwise calling SimpleRateThrottle will also directly report an error Must be overridden. May return `None` if the request should not be throttled. """ raise NotImplementedError('.get_cache_key() must be overridden')

4. Example

class FirstThrottle(SimpleRateThrottle): # The function self.get rate will be called here, and the returned value is 10/m scope = "thro_rate" # If not redefined, an error will be reported because it has to find the ip address from the cache def get_cache_key(self, request, view): # It's OK to return to null, and there will be a countdown return self.get_ident(request) # "detail": "Request was throttled. Expected available in 56 seconds."

5. Error log in Chinese

5.1 the first three steps of the process

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): # Enter throttled if not present self.throttled(request, throttle.wait())

5.2. throttled error prompt

def throttled(self, request, wait): """ If request is throttled, determine what kind of exception to raise. """ # Return error message raise exceptions.Throttled(wait)

5.3 rewrite exceptions method

class Throttled(APIException): status_code = status.HTTP_429_TOO_MANY_REQUESTS default_detail = _('Request was throttled.') extra_detail_singular = 'Expected available in second.' extra_detail_plural = 'Expected available in seconds.'

5.4. Example

from app01.SelfThrottle import FirstThrottle from rest_framework import exceptions class Thor(APIView): # Partial use throttle_classes = [FirstThrottle, ] def get(self, request, *args, **kwargs): return HttpResponse("ok") # Note that you need to override the method in the view class, or inherit def throttled(self, request, wait): class Myerrors(exceptions.Throttled): default_detail = "Frequency limit exceeded" extra_detail_singular = 'please Seconds later.' extra_detail_plural = 'please Seconds later.' raise Myerrors(wait)

10 November 2019, 09:49 | Views: 6557

Add new comment

For adding a comment, please log in
or create account

0 comments