您的位置:首页 > 编程语言 > Go语言

Django REST framework的各种技巧——6.异常处理

2016-02-01 19:22 597 查看
restframework内置了基本的异常处理,然而并不够用

Django REST framework的各种技巧【目录索引】

异常处理应该考虑的事情

异常时为了保持api的一致,应该返回json

error_code

给开发看的error_message

给用户看的message

开始怼代码

源码中的异常处理,可见是不符合需求的。

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, 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)
elif isinstance(exc, Http404):
msg = _('Not found.')
data = {'detail': six.text_type(msg)}

set_rollback()
return Response(data, status=status.HTTP_404_NOT_FOUND)

elif isinstance(exc, PermissionDenied):
msg = _('Permission denied.')
data = {'detail': six.text_type(msg)}

set_rollback()
return Response(data, status=status.HTTP_403_FORBIDDEN)

# Note: Unhandled exceptions will raise a 500 error.
return None

实现想要的handler

注意我在handler最后一行注释掉的代码,一定不能抓最后的异常,这样log的信息会没有各种堆栈,非常不全

class Error(Exception):

def __init__(self, err_code, err_message='Internal Server Error',
message=u'服务器异常', status_code=status.HTTP_400_BAD_REQUEST):
self.err_code = err_code
self.err_message = err_message
self.message = message
self.status_code = status_code

def __unicode__(self):
return u'[Error] %d: %s(%d)' % (self.err_code, self.err_message, self.status_code)

def getResponse(self):
return ErrorResponse(self.err_code, self.err_message, self.message, self.status_code)

def ErrorResponse(err_code=errors.SYSTEM_ERROR, err_message='Internal Server Error',
message=u'服务器异常', status=status.HTTP_400_BAD_REQUEST, headers=None):
err = {
'error_code': err_code,
'error': err_message,
'message': message,
}
return Response(err, status, headers=headers)

def custom_exception_handler(exc, context):

if isinstance(exc, Error):
set_rollback()
return ErrorResponse(exc.err_code, exc.err_message, exc.message, status=exc.status_code)

if isinstance(exc, (ForeignObjectRelDeleteError, ModelDontHaveIsActiveFiled)):
set_rollback()
return ErrorResponse(errors.PermissionDenied, unicode(exc), u'抱歉, 已有其他数据与之关联, 禁止删除', status=status.HTTP_403_FORBIDDEN)

if isinstance(exc, (RestPermissionDenied, PermissionDenied)):
msg = _('Permission denied.')
data = {
'detail': six.text_type(msg)
}
exc_message = str(exc)
if 'CSRF' in exc_message:
data['detail'] = exc_message

set_rollback()
return ErrorResponse(errors.PermissionDenied, data, u'opps, 您没有对应的权限', status=status.HTTP_403_FORBIDDEN)
....
log.error(exc)
# Note: Unhandled exceptions will raise a 500 error.
#return ErrorResponse(errors.SYSTEM_ERROR, 'Internal Server Error', status.HTTP_500_INTERNAL_SERVER_ERROR)

然后在settings.py中加上
'EXCEPTION_HANDLER': 'api.exception_handler.custom_exception_handler',


通过这样的实现你就可以直接在代码中丢异常了,而前端收到的是一个http code为400的json response

@POST('name', validators='required')
def create(self, request, name, *args, **kwargs):
try:
Term.objects.get(name=name, is_active=True)
raise Error(errors.Exist, err_message=u'已存在对应的年份', message=u'已存在对应的年份')
except Term.DoesNotExist:
pass
return super(TermsView, self).create(request, *args, **kwargs)

关于上面的500的json方式

使用django的自定义404,500handler的方式解决

url.py里面加上 handler500 = 'service.views.render_500'

def render_500(request):
if request.is_ajax():
err = {
'error_code': errors.SYSTEM_ERROR,
'error': 'Internal Server Error',
'message': 'Internal Server Error',
}
return JsonResponse(err, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
return redirect('/error/?c=500')
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  django restful 异常