Django의 DRF 소스 분석(4) - 주파수 인증 구성 요소
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):
self.throttled(request, throttle.wait())
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 get_cache_key(self, request, view):
# , ip,
"""
Should return a unique cache-key which can be used for throttling.
Must be overridden.
May return `None` if the request should not be throttled.
"""
raise NotImplementedError('.get_cache_key() must be overridden')
def get_rate(self):
"""
Determine the string representation of the allowed request rate.
"""
# SimpleRateThrottle scope , , , if
if not getattr(self, 'scope', None):
msg = ("You must set either `.scope` or `.rate` for '%s' throttle" %
self.__class__.__name__)
raise ImproperlyConfigured(msg)
try:
# scope settings.py REST_FRAMEWORK DEFAULT_THROTTLE_RATES "qzk":"3/m"
return self.THROTTLE_RATES[self.scope]
except KeyError:
msg = "No default throttle rate set for '%s' scope" % self.scope
raise ImproperlyConfigured(msg)
def parse_rate(self, rate):
"""
Given the request rate string, return a two tuple of:
,
"""
if rate is None:
return (None, None)
# "/" , num,period
num, period = rate.split('/')
# num
num_requests = int(num)
# period = “m” “minute”
# duration {...}["m"]
# period[0] ( 0)
duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]
# num_reuqets=3 duration=60
return (num_requests, duration)
def allow_request(self, request, view):
"""
Implement the check to see if the request should be throttled.
On success calls `throttle_success`.
throttle_success
On failure calls `throttle_failure`.
`throttle_failure`
"""
if self.rate is None:
return True
# self.key ip( ), , key
self.key = self.get_cache_key(request, view)
# ip none
if self.key is None:
return True
# ip self.cache value---> [ctime2,ctime1]
self.history = self.cache.get(self.key, []) # self.history
#
self.now = self.timer()
# Drop any requests from the history which have now passed the
# throttle duration
# ( ) <= - (60)
while self.history and self.history[-1] <= self.now - self.duration:
self.history.pop() # pop ( )
if len(self.history) >= self.num_requests: # >= (3)
return self.throttle_failure() # False
return self.throttle_success() # True
def throttle_success(self):
"""
Inserts the current request's timestamp along with the key
into the cache.
"""
self.history.insert(0, self.now) #
self.cache.set(self.key, self.history, self.duration) #
return True
def throttle_failure(self):
"""
Called when a request to the API has failed due to throttling.
"""
return False
def wait(self):
"""
Returns the recommended next request time in seconds.
"""
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)
BaseThrottle 클래스
class BaseThrottle(object):
"""
Rate throttling of requests.
"""
def allow_request(self, request, view):
"""
Return `True` if the request should be allowed, `False` otherwise.
"""
raise NotImplementedError('.allow_request() must be overridden')
def get_ident(self, request):
"""
Identify the machine making the request by parsing HTTP_X_FORWARDED_FOR
if present and number of proxies is > 0. If not use all of
HTTP_X_FORWARDED_FOR if it is available, if not use REMOTE_ADDR.
"""
#
xff = request.META.get('HTTP_X_FORWARDED_FOR')
# ip
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):
"""
Optionally, return a recommended number of seconds to wait before
the next request.
"""
return None
""" """
'''
( SimpleRateThrottle) ---> scope ---> get_cache_key self.get_ident(request)---->
:
1.APIView
2.---->dispatch
3.---->self.initial(request, *args, **kwargs)
4.---->self.check_throttles(request)
5.---->throttle.allow_request(request, self)
6.---->self.get_cache_key(request, view)( )( ip)
7.---->self.cache.get(self.key, []) ip ip
8.----> (self.rate,self.num_requests,self.duration) (__init__):
8.1--> self.rate = self.get_rate()-->self.THROTTLE_RATES[self.scope]
-->api_settings.DEFAULT_THROTTLE_RATES( )
self.rate ---> 'qzk':'3/m'
8.2-->self.num_requests, self.duration = self.parse_rate(self.rate)
self.num_requests (3)
self.duration (60)
9.----> , ,
True:——> throttle_success:
self.history.insert(0, self.now) #
# key,history,duration {}
self.cache.set(self.key, self.history, self.duration)
False :---> throttle_failure , Ture
'''
전재 대상:https://www.cnblogs.com/qianzhengkai/p/11134495.html
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.