python_restframework
2023-01-31 01:01:31
python
(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 = []
使用组件中自带的频率控制组件
先在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)
相关文章