全局异常捕获
drf只会捕获属于drf的异常,所以要做到全局异常捕获,还需要手动操作一下。
经过对drf异常处理组件的源码分析之后可以得知,其实就是自己定义一个exception_handler函数,然后全局替换一下即可
首先要知道,虽然是自己写一个exception_handler函数,但是drf的exception_handler也还是有用的,因为drf已经帮我们处理好了,drf的异常,我们只需要处理其他的异常即可
通过读exception_handler文件可知,只要返回的是None,那么该异常不属于drf
from rest_framework.views import exception_handler, APIView
from rest_framework.response import Response
# 自定义异常类
class PasswordException(Exception):
def __init__(self, msg):
self.msg = msg
def common_exception_handler(exc, context):
# 下面这一堆都是获取日志内容的信息
request = context['request']
ip = request.META.get('REMOTE_ADDR')
path = 'http://127.0.0.1:8000' + request.get_full_path()
method = request.method
view = context['view']
user_id = request.user.pk or '游客登录'
print(f"请求方式:{method},请求地址:{path},访问ip:{ip},出错地址:{view},用户id:{user_id}")
# 调用drf内置的exception_handler函数
res = exception_handler(exc, context)
# 如果没有res,就说明不是drf的报错
# 所以需要自己处理,正常返回Response对象,做到真正的全局异常捕获
if not res:
return Response({'code': 301, 'message': f'自己的问题哦:>>>{str(exc)}'})
#
if isinstance(res.data, dict):
return Response({'code': 302, 'message': f'drf的问题:>>>{res.data.get("detail")}'})
return Response({'code': 302, 'message': f'drf的问题:>>>{res.data[0]}'})
异常捕获源码解析
# 首先看dispath
# 这里面首先做了三大认证,然后做了异常捕获处理
def dispatch(self, request, *args, **kwargs):
self.args = args
self.kwargs = kwargs
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers
try:
# 这一步是在做三大认证
self.initial(request, *args, **kwargs)
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
response = handler(request, *args, **kwargs)
except Exception as exc:
# 做了异常捕获
# 点进handle_exception往下看
response = self.handle_exception(exc)
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
# 可以看到做了一堆if判断,最后是要返回一个response
def handle_exception(self, exc):
if isinstance(exc, (exceptions.NotAuthenticated,
exceptions.AuthenticationFailed)):
auth_header = self.get_authenticate_header(self.request)
if auth_header:
exc.auth_header = auth_header
else:
exc.status_code = status.HTTP_403_FORBIDDEN
# 点进去看 会发现 get_exception_handler是配置文件中的一个函数 看下面的代码块
exception_handler = self.get_exception_handler()
context = self.get_exception_handler_context()
# 从这里可以看出上面的exception_handler是一个内存地址
response = exception_handler(exc, context)
# 如果response是None就抛异常 反之正常返回
if response is None:
self.raise_uncaught_exception(exc)
response.exception = True
return response
def exception_handler(exc, context):
if isinstance(exc, Http404):
exc = exceptions.NotFound()
elif isinstance(exc, PermissionDenied):
exc = exceptions.PermissionDenied()
# 这一步就是判断 当前的异常是不是属于drf内置的类的对象
# 如果是 则返回前端可以渲染的 Response
# 如果不是 则返回None 前端就会爆出错误信息
if isinstance(exc, exceptions.APIException):
headers = {}
if getattr(exc, 'auth_header', None):
headers['WWW-Authenticate'] = exc.auth_header
if getattr(exc, 'wait', None):
headers['Retry-After'] = '%d' % exc.wait
if isinstance(exc.detail, (list, dict)):
data = exc.detail
else:
data = {'detail': exc.detail}
set_rollback()
return Response(data, status=exc.status_code, headers=headers)
return None
标签:exception,exc,handler,self,request,response,源码,全局,捕获
From: https://www.cnblogs.com/Hqqqq/p/18149601