datetime:2020/1/8 16:02
author:nzb
重写异常处理返回
例如:
- 正常返回
{ "detail": "方法 “GET” 不被允许。" }
- 重写返回
{ "code": 10001, "errMsg": "方法 “GET” 不被允许。" }
源码流程
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 # 活动到某个视图的某个方法,例如create() # 视图函数里的serializer.is_valid(raise_exception=True), # 会去验证序列化里面自带的验证规则和自定义的验证规则(并抛出异常) 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
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()
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
# 获取配置文件
def get_exception_handler(self):
"""
Returns the exception handler that this view uses.
"""
return self.settings.EXCEPTION_HANDLER
重写函数custom_exception_handler()
from rest_framework.views import exception_handler
def custom_exception_handler(exc,context):
"""
框架自带错误码(常见已知的)
( (400, "invalid"),
(401, "authentication_failed"),
(401, "not_authenticated"),
(403, "permission_denied"),
(404, "not_found"),
(405, "method_not_allowed"),
)
不常见的
( (400, "parse_error"),
(406, "not_acceptable"),
(415, "unsupported_media_type"),
(429, "throttled")
)
"""
response = exception_handler(exc, context) # 获取本来应该返回的exception的response
request = context.get("request", None)
...
if response is not None:
if response.status_code == 403: # 权限
pass
elif response.status_code == 401: # 是否登录
pass
elif response.status_code == 404: # 资源未找到
response.data['code'] = org_status_code.NOTFOUNDERROR_CODE.get("code", None)
response.data['errMsg'] = org_status_code.NOTFOUNDERROR_CODE.get("detail", None)
del response.data['detail']
elif response.status_code == 405: # 方法不允许
pass
elif response.status_code == 400: # 重写django自带的序列化错误以及自定义的序列化错误
response = process_400_BAD_REQUEST(response)
else:
pass
return response
def process_400_BAD_REQUEST(response):
"""映射自带错误和返回自定义错误"""
old_data = response.data
for k, v in old_data.items():
new_data = {}
# 框架自带错误码(常见已知的)
if v[0].code == "required":
new_data['code'] = org_status_code.NOTNULL_CODE.get("code", None)
new_data['errMsg'] = org_status_code.NOTNULL_CODE.get("detail", None).format(k)
elif v[0].code == "invalid":
new_data['code'] = org_status_code.TYPEERROR_CODE.get("code", None)
new_data['errMsg'] = org_status_code.TYPEERROR_CODE.get("detail", None).format(k, v[0])
elif v[0].code == "incorrect_type": # 类型错误
new_data['code'] = org_status_code.TYPEERROR_CODE.get("code", None)
new_data['errMsg'] = org_status_code.TYPEERROR_CODE.get("detail", None).format(k, v[
0]) # "{0}字段{1}".format(k, v[0])
elif v[0].code == "does_not_exist": # 外键对象不存在
new_data['code'] = org_status_code.FOREIGNKEYNOEXISTED_CODE.get("code", None)
new_data['errMsg'] = org_status_code.FOREIGNKEYNOEXISTED_CODE.get("detail", None).format(k, v[
0]) # "{0}字段{1}".format(k, v[0])
elif v[0].code == "unique": # 已存在
new_data['code'] = org_status_code.EXISTED_CODE.get("code", None)
new_data['errMsg'] = org_status_code.EXISTED_CODE.get("detail", None)
elif v[0].code == "max_length": # 最大长度
new_data['code'] = org_status_code.MAXLENGTHERROR_CODE.get("code", None)
new_data['errMsg'] = v[0].replace("这个", k)
elif v[0].code == "min_length": # 最小长度
new_data['code'] = org_status_code.MINLENGTHERROR_CODE.get("code", None)
new_data['errMsg'] = v[0].replace("这个", k)
# 自定义错误码以及未知的错误码
else:
if isinstance(v[0].code, int): # 自定义的错误
new_data['code'] = v[0].code
new_data['errMsg'] = v[0]
else:
response.data = old_data
return response
response.data = new_data
return response
settings.py配置
REST_FRAMEWORK = {
'DATETIME_FORMAT': '%Y/%m/%d %H:%M:%S',
'JWT_ALLOW_REFRESH': True,
'DEFAULT_AUTHENTICATION_CLASSES': (
"rest_framework_jwt.authentication.JSONWebTokenAuthentication",
# 'utils.authentication.CustomAuthenticate', # 自定义 JSON Token Authentication
# 'rest_framework.authentication.BasicAuthentication',
# 'rest_framework.authentication.SessionAuthentication',
),
'EXCEPTION_HANDLER': 'utils.exceptions.custom_exception_handler', # 自定义重写的异常处理返回
'SEARCH_PARAM': 'kw',
}