python_restframework(頻率組件)
阿新 • • 發佈:2019-05-16
key either 管理 ror prop 一次 remote available not BaseThrottle
(1) 取出訪問者ip
(2) 判斷當前ip不在訪問字典裏,添加進去,並且直接返回True,表示第一次訪問,在字典裏,繼續往下走
(3) 循環判斷當前ip的列表,有值,並且當前時間減去列表的最後一個時間大於60s,把這種數據pop掉,這樣列表中只有60s以內的訪問時間,
(4) 判斷,當列表小於3,說明一分鐘以內訪問不足三次,把當前時間插入到列表第一個位置,返回True,順利通過
(5) 當大於等於3,說明一分鐘內訪問超過三次,返回False驗證失敗
1、分發display
def dispatch(self, request, *args, **kwargs): try: # 進入初始化 self.initial(request, *args, **kwargs)
2、 drf初始化方法
APIview下的方法
def initial(self, request, *args, **kwargs):
# 認證
self.perform_authentication(request)
# 進入權限
self.check_permissions(request)
# --> 頻率
self.check_throttles(request)
3、頻率模塊
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(): # 返回結果true or false, false就繼續執行 if not throttle.allow_request(request, self): # 視圖類的三個參數, self, request, # throttle.wait(): 最後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.
"""
# 跟權限組件一樣, 這裏循環 return出去的也是一個列表
return [throttle() for throttle in self.throttle_classes]
3.2、if 判斷
# 當返回為false時,說明該用戶或訂單無此權限, # not false為true 繼續往下執行, not true就是 false, 不執行下面代碼 if not throttle.allow_request(request, self):
3.3、throttle.allow_request
# 如果是false 就直接返回這個錯誤了
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
# 繼承基礎的認證權限, 如果忘了要定義哪個類 直接在這裏看也OK
from rest_framework.throttling import BaseThrottle
# 自定義的組件
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
# 最後要返回的時間或者其它
def wait(self):
return None
5、定義一個權限
class MyPermission(BasePermission):
# 前臺返回的錯誤
message = "您沒有權限, 請先聯系下管理員增加權限"
# 獲取權限
def has_permission(self,request, view):
# 認證組件, 返回的request.user
print("permission: ", request.user.permission)
if request.user.permission > 1:
# 如果大於就是true, 在第3步,if not true 等於false就不執行它了
return True
return False
6、頻率組件
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: 瀏覽器請求過來的數據
:param view: apiview視圖
:return: true or false
# 1、取出訪問者的IP
client_ip = request.META.get("REMOTE_ADDR")
self.ip = client_ip
# 2、判斷不存在的話添加到字典 並將時間也一並添加進去
if client_ip not in self.get_ip:
self.get_ip[client_ip] = [self.ctime, ]
return True
# 獲取當前IP的訪問時間記錄
self.history = self.get_ip[client_ip]
# 3、 開始循環判斷, 如果最後一個大於60秒就直接幹掉
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、全局使用頻率
# settings.py文件中定義, 所有的組件都可以放在這裏
REST_FRAMEWORK = {
"DEFAULT_THROTTLE_CLASSES": [
‘app01.myauth.FirstThrottle‘, # 全局使用權限
]
}
7、局部使用
類中直接使用
throttle_classes = [FirstThrottle, ]
8、局部禁用
類中直接使用
throttle_classes = []
SimpleRateThrottle
使用組件中自帶的頻率控制組件
先在settings.py中定義限制頻率的範圍 REST_FRAMEWORK={ "DEFAULT_THROTTLE_RATES": { "thro_rate": "10/m" } }
1、進入頻率
class SimpleRateThrottle(BaseThrottle):
cache = default_cache
# 獲取時間
timer = time.time
cache_format = ‘throttle_%(scope)s_%(ident)s‘
# 這個是在setting中設置的 DEFAULT_THROTTLE_RATES的字典key, 必須得定義
scope = None
THROTTLE_RATES = api_settings.DEFAULT_THROTTLE_RATES
# 初始化,
def __init__(self):
# 首先就是先判斷 rate是否為空, 如果是false為空,就進入self.get_rate
if not getattr(self, ‘rate‘, None):
# 直接輸出錯誤
self.rate = self.get_rate()
# 如果上一步通過,就繼續進入這裏 9.2
self.num_requests, self.duration = self.parse_rate(self.rate)
# 也就是說執行完9.2之後 獲取到的結果就是
# self.num_requests, self.duration = (10,60)
1.1、get_rate
def get_rate(self):
# scope 這個值在類中必須被定義成 settings中定義的值 如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:
# 在配置文件中 將thro_rate 取出, 返回 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、當初始化通過
? 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>
"""
# 這個是在setting中設置的 DEFAULT_THROTTLE_RATES的字典設置為空,就直接返回none,none
if rate is None:
return (None, None)
# 這裏的rate就是就是get_rate取出來的10/m 然後切割它
num, period = rate.split(‘/‘)
num_requests = int(num)
# 定義如果是m就是60秒,然後字典中直接取值這裏是m取出來的就是60
duration = {‘s‘: 1, ‘m‘: 60, ‘h‘: 3600, ‘d‘: 86400}[period[0]]
# 最後返回它倆
return (num_requests, duration)
3、類中調用get_cache_key
def get_cache_key(self, request, view):
"""
# 應返回可用於限制的唯一緩存鍵。
Should return a unique cache-key which can be used for throttling.
# 必須要重寫, 否則調用SimpleRateThrottle也會直接報錯
Must be overridden.
May return `None` if the request should not be throttled.
"""
raise NotImplementedError(‘.get_cache_key() must be overridden‘)
4、實例
class FirstThrottle(SimpleRateThrottle):
# 這裏會調用 self.get_rate那個函數,返回的就是 10/m了
scope = "thro_rate"
# 如果不重新定義就會報錯, 因為它得從緩存中找出 ip地址
def get_cache_key(self, request, view):
# 返回空也行, 也會有倒計時
return self.get_ident(request)
# "detail": "Request was throttled. Expected available in 56 seconds."
5、中文顯示錯誤日誌
5.1、流程的前3步
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):
# 如果不存在 就進入到 throttled中
self.throttled(request, throttle.wait())
5.2、throttled 錯誤提示
def throttled(self, request, wait):
"""
If request is throttled, determine what kind of exception to raise.
"""
# 返回錯誤信息
raise exceptions.Throttled(wait)
5.3、重寫exceptions方法
class Throttled(APIException):
status_code = status.HTTP_429_TOO_MANY_REQUESTS
default_detail = _(‘Request was throttled.‘)
extra_detail_singular = ‘Expected available in {wait} second.‘
extra_detail_plural = ‘Expected available in {wait} seconds.‘
5.4、實例
from app01.SelfThrottle import FirstThrottle
from rest_framework import exceptions
class Thor(APIView):
# 局部使用
throttle_classes = [FirstThrottle, ]
def get(self, request, *args, **kwargs):
return HttpResponse("ok")
# 需要註意的是 這裏需要在視圖類的重寫方法,或繼承
def throttled(self, request, wait):
class Myerrors(exceptions.Throttled):
default_detail = "超出頻率限制"
extra_detail_singular = ‘請 {wait} 秒後在訪問.‘
extra_detail_plural = ‘請 {wait} 秒後在訪問.‘
raise Myerrors(wait)
python_restframework(頻率組件)