自定义频率类,全局异常处理
作者:互联网
1 自定义频率类
# 自定义的逻辑
#(1)取出访问者ip {192.168.1.12:[访问时间3,访问时间2,访问时间1],192.168.1.12:[],192.168.1.14:[]}
#(2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问,在字典里,继续往下走
#(3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
#(4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过
#(5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败
1.1 具体实现
from rest_framework.throttling import BaseThrottle
class MyThrottling():
VISIT_RECORD = {}
def __init__(self):
self.history = None
def allow_request(self, request, view):
# (1)取出访问者ip
ip = request.META.get('REMOTE_ADDR')
import time
ctime = time.time()
# (2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问
if ip not in self.VISIT_RECORD:
self.VISIT_RECORD[ip] = [ctime, ]
return True
self.history = self.VISIT_RECORD.get(ip)
# (3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
while self.history and ctime - self.history[-1] > 60:
self.history.pop()
# (4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过
# (5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败
if len(self.history) < 3:
self.history.insert(0, ctime)
return True
else:
return False
def wait(self):
import time
ctime = time.time()
return 60 - (ctime - self.history[-1])
2 权限,频率执行源码分析(了解)
2.1 权限源码执行流程
# APIView的dispatch---》self.initial(request, *args, **kwargs)---》415行self.check_permissions(request)--->
def check_permissions(self, request):
for permission in self.get_permissions(): #配在视图类上的权限类列表对象
if not permission.has_permission(request, self):
self.permission_denied(
request,
message=getattr(permission, 'message', None),
code=getattr(permission, 'code', None)
)
2.2 频率源码执行流程
# APIView的dispatch---》self.initial(request, *args, **kwargs)---》416行self.check_throttles(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())
if throttle_durations:
durations = [
duration for duration in throttle_durations
if duration is not None
]
duration = max(durations, default=None)
self.throttled(request, duration)
# 你写的频率类一定要重写allow_request,返回True就是没有频率限制住,返回False就是被频率限制了
# 咱们第一天写的,继承SimpleRateThrottle---》它肯定重写了allow_request---》今天写的逻辑跟源码一样
SimpleRateThrottle---》allow_request---》
def __init__(self):
if not getattr(self, 'rate', None):
# self.rate 现在是 '3/m'
self.rate = self.get_rate()
# 3 60
self.num_requests, self.duration = self.parse_rate(self.rate)
def allow_request(self, request, view):
if self.rate is None: # 只要配在文件配了,它就有值,在init中
return True
# 现在的唯一字符串
# ip地址
self.key = self.get_cache_key(request, view)
if self.key is None:
return True
# [时间2,时间1]
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() #把所有超过60的数据都剔除,self.history只剩60s以内的访问时间
if len(self.history) >= self.num_requests: #大于等于配置的数字3
return self.throttle_failure() # return False
return self.throttle_success() # 把当前时间插入,retrun True
3 全局异常处理(重要)
# drf配置文件中,已经配置了,但是它不符合咱们的要求
# drf的配置文件:'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler',
# 如果抛了异常,就会执行exception_handler函数
# 重新写一个函数,如果出了异常,执行我们的函数
# drf默认的异常处理,只处理了drf自己的异常:所有drf中抛的异常,都有detail,django的异常,抛出很长的xml数据
{
"detail": "小伙子,你错了"
}
{
code:999
msg:"小伙子,你错了"
}
使用步骤
# 第一步:写一个函数
from rest_framework.views import exception_handler
from rest_framework.response import Response
def common_exception_handler(exc, context):
# 正常来讲,在这里需要记录日志---》如何在django中记录日志后面讲
# 日志记录,越详细越好:哪个用户(id,ip),在什么时间,执行哪个视图函数时报了错,请求地址是什么
print(context['view']) #视图类的对象
print(context['request']) #当前请求的对象----》ip,用户id,当前时间,请求地址来
view=context['view']
request=context['request']
print('ip地址为:%s的用户,访问:%s 视图类,报错了,请求地址是:%s'%(request.META.get('REMOTE_ADDR'),str(view),request.path))
response=exception_handler(exc, context)
if response: # 这是drf的异常,其实人家已经处理了,但是不符合我的格式 {code:999,msg:错误}
res=Response({'code':999,'msg':response.data.get('detail')})
else:
# res=Response({'code':998,'msg':'服务器错误,请联系系统管理员'})
res=Response({'code':998,'msg':str(exc)})
return res
# 第二步:把函数配置在配置文件中
REST_FRAMEWORK = {
# 自己写的全局异常捕获
'EXCEPTION_HANDLER': 'app01.exceptions.common_exception_handler',
}
4 自动生成接口文档
# 后端人员,写好接口,提供接口文档给前端用
# 如何编写接口文档
-使用word写,md写----》提交到git上
-公司有接口文档平台---》后端人员在文档平台录入数据---》公司自己开发,yapi(百度开源),第三方
-https://zhuanlan.zhihu.com/p/366025001 自己搭建yapi
-https://www.showdoc.com.cn/ 第三方平台
- 自动生成接口文档---》项目写好了,一键生成接口文档----》一键生成---》导出---》导入到yapi
# drf中自动生成接口文档
-coreapi,swagger(更通用一些,go,java)
-安装 pip3 install coreapi
-在项目中配置
-加入路由:
from rest_framework.documentation import include_docs_urls
urlpatterns = [
path('docs/', include_docs_urls(title='站点页面标题'))
]
-配置文件中配置
REST_FRAMEWORK = {
'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',
}
-尽管写接口,写注释,会自动生成
5 RBAC介绍(面试)
# RBAC 是基于角色的访问控制(Role-Based Access Control )在 RBAC 中,
权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。这样管理都是层级相互依赖的,权限赋予给角色,而把角色又赋予用户,这样的权限设计很清楚,管理起来很方便
# 这种设计,在公司内部系统用的多,对外的系统基本不用
# 权限:真正的权限,比如发工资,招人,申请测试机
# 角色:(组,部门) 角色下有很多员工
# 用户:一个个的人
# 用户和角色关系是多对多,中间表
# 权限和角色关系是多对多,中间表
# 权限和用户的中间表
#前后端分离项目控制权限---》权限类中
#前后端混合
-django框架在公司里用的很多,写内部项目,肯定要用权限控制,用的就是rbac,自己实现一套,django内置了后台管理,自带rbac(admin+auth)
-基于django的admin二次开发
-美化:xadmin(基本不用了,2.x以后django不兼容多,作者弃坑了)
-simpleui:
-django+drf+vue=djagnovueadmin 一款前后端分离的自带rbac的后台管理框架
# django的admin基于rbac
-auth_user #用户表
-auth_permission #权限表
-auth_group #组,角色表
-auth_user_groups # 用户和组中间表
-auth_group_permissions #组和权限中间表
-auth_user_user_permissions #用户和权限中间表
标签:自定义,ip,self,request,---,频率,全局,权限,history 来源: https://www.cnblogs.com/chunyouqudongwuyuan/p/16402221.html