异常模块源码入口
APIView
类中dispatch
方法中的:response = self.handle_exception(exc)
源码分析
我们点击handle_exception
跳转,查看该方法源码
def handle_exception(self, exc):
"""
Handle any exception that occurs, by returning an appropriate response,
or re-raising the error.
"""
# 判断异常类型是否是没有认证的类型,最后返回403状态码
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()
# 获取异常的上下文
context = self.get_exception_handler_context()
# 返回异常响应
response = exception_handler(exc, context)
# 如果响应为内容为空,则抛出异常
if response is None:
self.raise_uncaught_exception(exc)
response.exception = True
return response
以上源码最为关键的一句就在于exception_handler = self.get_exception_handler()
,我们可以点击查看该方法源码
def get_exception_handler(self):
"""
Returns the exception handler that this view uses.
"""
return self.settings.EXCEPTION_HANDLER
该方法返回该视图的异常处理方法,从返回的内容,我们可以知道,该方法在settings
文件中有个默认值,进入settings
可查看到
'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler',
异常处理的默认方法就是views
下的exception_handler
方法,我们再进入查看该方法源码
def exception_handler(exc, context):
"""
Returns the response that should be used for any given exception.
By default we handle the REST framework `APIException`, and also
Django's built-in `Http404` and `PermissionDenied` exceptions.
Any unhandled exceptions may return `None`, which will cause a 500 error
to be raised.
"""
# 判断异常是否是404
if isinstance(exc, Http404):
exc = exceptions.NotFound()
# 判断异常是否是没有权限
elif isinstance(exc, PermissionDenied):
exc = exceptions.PermissionDenied()
# 判断异常是否是drf的基类异常,该异常提供了状态码和异常字段detail
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
# 判断detail是否是list类型或dict类型
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
从上述代码我们可以知道,当response
返回为None
时,是不会返回异常信息,而是直接抛出异常,所以我们可以自定义异常类
自定义异常
在我们的app
目录下,创建utils
包,并创建exceptions
文件,并写入如下源码:
from rest_framework.response import Response
from rest_framework.views import exception_handler as drf_exception_handler
def exception_handler(exc, context):
response = drf_exception_handler(exc, context)
if response is None:
print(f"{context['view']} - {context['request'].method} - {exc}")
return Response(status=500, data="服务器错误")
return response
最后我们将默认异常信息配置改为自己的配置即可,在settings
文件中写入如下配置
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'drf_app.utils.exceptions.exception_handler',
}
以后碰到response
响应为None
的时候,我们就会抛出服务器错误的异常信息
总结
为什么要自定义异常模块?
- 所有经过
drf
的APIView
视图类产生的异常,都可以提供异常处理方案 drf
默认提供了异常处理方案(rest_framework.views.exception_handler)
,但是处理范围有限drf
提供的处理方案两种,处理了返回异常现象,没处理返回None
(后续就是服务器抛异常给前台)- 自定义异常的目的就是解决
drf
没有处理的异常,让前台得到合理的异常信息返回,后台记录异常具体信息