drf - 异常源码分析及自定义异常处理
目录
异常部分源码分析
1. 在rest_framework.views的dispath方法中
def dispatch(self, request, *args, **kwargs):
"""
`.dispatch()` is pretty much the same as Django's regular dispatch,
but with extra hooks for startup, finalize, and exception handling.
"""
self.args = args
self.kwargs = kwargs
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate?
try:
# 三大验证
self.initial(request, *args, **kwargs)
# Get the appropriate handler method
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:
response = self.handle_exception(exc) # 捕获万能异常并处理
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
2.有异常时,调用 handle_exception 方法
def handle_exception(self, exc):
"""
Handle any exception that occurs, by returning an appropriate response,
or re-raising the error.
"""
# 处理认证失败异常
if isinstance(exc, (exceptions.NotAuthenticated,
exceptions.AuthenticationFailed)):
# WWW-Authenticate header for 401 responses, else coerce to 403
auth_header = self.get_authenticate_header(self.request)
if auth_header:
exc.auth_header = auth_header
else:
exc.status_code = status.HTTP_403_FORBIDDEN
# 获取异常句柄
exception_handler = self.get_exception_handler() # self.settings.EXCEPTION_HANDLER,默认指向 rest_framework.views.exception_handler函数
context = self.get_exception_handler_context() # 获取异常处理的内容
response = exception_handler(exc, context) # 调用exception_handler方法处理异常
# 如果response为None,则是exception_handler中未捕获到的异常
if response is None:
self.raise_uncaught_exception(exc)
response.exception = True
return response
3.调用 exception_handler 方法处理异常
def exception_handler(exc, context):
# Http404异常处理
if isinstance(exc, Http404):
exc = exceptions.NotFound()
# PermissionDenied权限异常处理
elif isinstance(exc, PermissionDenied):
exc = exceptions.PermissionDenied()
# APIException异常处理
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)
# 未捕获到的异常,返回None
return None
自定义异常处理
可见如果需要自定义异常处理,只需要重写exception_handler 方法。将exception_handler指向我们所写的 exception_handler 方法
setting.py文件添加配置
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'apis.exceptions.exception_handler',
}
exceptions.py文件重写exception_handler方法
from rest_framework.response import Response
from rest_framework.views import exception_handler as drf_exception_handler
def exception_handler(exc,context):
# drf的异常还是提交给 drf_exception_handler,我们只需要处理drf未处理的异常
response = drf_exception_handler(exc,context)
if response is None:
# drf 处理不了的异常
# 可以在此通过 logging 记录异常日志
return Response({
'exception':'服务器异常'
}, status=500)
response.exception = True
return response