框架报错源码解析
exception 处理器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32# rest_framework.views 71-101
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.
"""
if isinstance(exc, Http404):
exc = exceptions.NotFound()
elif isinstance(exc, PermissionDenied):
exc = exceptions.PermissionDenied()
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从处理器源码可以看到,当抛出一个
str的错误的时候,处理器会主动为其添加一个detail的key来包裹成可以被后续处理为json的格式,而对于list与dict的格式,则直接返回。ValidationError 处理
1 | #rest_framework.exceptions.ValidationError 140-158 |
对于ValidationError错误,会强制将最后的值转换为list类型,这是考虑到一个field可能有多条不同的错误需要累积。
- 序列化报错处理
1 | #rest_framework.serializers 323-346 |
drf中的序列化器serializers,在运行run_validation序列化报错的过程中,会给没有列出具体字段错误的detail信息,即不是dict格式的信息,带上一个non_field_errors的key来标准化。
推荐方案
- 非400报错
对于403,404等错误码,直接获取detail下的值即可 - 400报错
对于ValidationError错误,需要做两种处理- 单独创建,报错如下,直接识别到错误的字段
1
2
3{
"id": ["Not Unique"]
} - 批量创建,报错如下,按顺序识别创建的条目的错误字段。如果为空,则说明无校验错误。此外,关于返回值为数组,需要前端进行相应处理具有多个错误信息的报错。
1
2
3
4
5
6
7
8[
{},
{
"id": ["Not Unique"]
},
{},
{}
]其他方案
根据参考方案,按照团队习惯,可以自定义exception_handler,以定义团队使用的错误信息格式。参考文档
drf-exception
- 单独创建,报错如下,直接识别到错误的字段