在Django Rest Framework(DRF)中,全局异常处理是一种重要的机制,它可以帮助我们更好地管理API中的异常情况,并返回统一的错误响应。本文将详细介绍两种全局异常处理的方法:使用中间件(Middleware)和使用DRF内置的异常处理机制(ExceptionHandler)。
1. 使用中间件进行异常处理
中间件是Django中的一个通用概念,它可以用于全局性的请求和响应处理。我们可以通过自定义中间件来捕获API请求中的异常,并返回统一的错误响应。
步骤1:配置中间件
首先,在项目的settings.py
文件中添加我们自定义的异常处理中间件。
# settings.py
MIDDLEWARE = [
# ...
# 异常处理中间件
'utils.middleware.ExceptionMiddleware',
]
步骤2:自定义中间件
然后,在utils/middleware.py
文件中定义我们的异常处理中间件。
# utils/middleware.py
import logging
from django.db import DatabaseError
from django.http.response import JsonResponse
from django.http import HttpResponseServerError
from django.middleware.common import MiddlewareMixin
from rest_framework import status
from rest_framework.response import Response
from utils.enums import *
from utils.exceptions import *
from utils.result import R
logger = logging.getLogger('django')
class ExceptionMiddleware(MiddlewareMixin):
"""统一异常处理中间件"""
def process_exception(self, request, exception):
"""
统一异常处理
:param request: 请求对象
:param exception: 异常对象
:return:
"""
if isinstance(exception, BusinessException):
# 业务异常处理
data = R.set_result(exception.enum_cls).data()
return JsonResponse(data)
elif isinstance(exception, DatabaseError):
# 数据库异常
r = R.set_result(StatusCodeEnum.DB_ERR)
logger.error(r.data(), exc_info=True)
return HttpResponseServerError(StatusCodeEnum.SERVER_ERR.errmsg)
elif isinstance(exception, Exception):
# 服务器异常处理
r = R.server_error()
logger.error(r.data(), exc_info=True)
return HttpResponseServerError(r.errmsg)
return None
步骤3:自定义异常类和状态码枚举
在utils/exceptions.py
和utils/enums.py
文件中,我们可以定义自己的异常类和状态码枚举类。
# utils/exceptions.py
class CommonException(Exception):
"""公共异常类"""
def __init__(self, enum_cls):
self.code = enum_cls.code
self.errmsg = enum_cls.errmsg
self.enum_cls = enum_cls # 状态码枚举类
super().__init__()
class BusinessException(CommonException):
"""业务异常类"""
pass
class APIException(CommonException):
"""接口异常类"""
pass
# utils/enums.py
class StatusCodeEnum(Enum):
"""状态码枚举类"""
OK = (0, '成功')
ERROR = (-1, '错误')
SERVER_ERR = (500, '服务器异常')
# ... 其他状态码
步骤4:响应信息封装
在utils/result.py
文件中,我们可以定义一个统一项目信息返回结果类。
# utils/result.py
class R(object):
"""
统一项目信息返回结果类
"""
def __init__(self):
self.code = None
self.errmsg = None
self._data = dict()
@staticmethod
def ok():
"""
组织成功响应信息
:return:
"""
r = R()
r.code = StatusCodeEnum.OK.code
r.errmsg = StatusCodeEnum.OK.errmsg
return r
@staticmethod
def error():
"""
组织错误响应信息
:return:
"""
r = R()
r.code = StatusCodeEnum.ERROR.code
r.errmsg = StatusCodeEnum.ERROR.errmsg
return r
@staticmethod
def server_error():
"""
组织服务器错误信息
:return:
"""
r = R()
r.code = StatusCodeEnum.SERVER_ERR.code
r.errmsg = StatusCodeEnum.SERVER_ERR.errmsg
return r
@staticmethod
def set_result(enum):
"""
组织对应枚举类的响应信息
:param enum: 状态枚举类
:return:
"""
r = R()
r.code = enum.code
r.errmsg = enum.errmsg
return r
def data(self, key=None, obj=None):
"""统一后端返回的数据"""
if key:
self._data[key] = obj
context = {
'code': self.code,
'errmsg': self.errmsg,
'data':self._data
}
return context
步骤5:测试视图
最后,在视图中抛出我们自定义的异常,以测试我们的异常处理机制是否有效。
# views.py
from rest_framework.decorators import api_view
from rest_framework.views import APIView
from utils.enums import StatusCodeEnum
from utils.exceptions import *
class TestView(APIView):
@api_view(['POST'])
def verify_params(request):
"""
校验注册信息
:param request: 注册请求对象
:return: response_ret
"""
# 接受参数
params = get_parameter_dic(request)
username = params.get('username')
mobile = params.get('mobile')
# 校验参数
all_args = [username, mobile]
if not all(all_args):
raise BusinessException(StatusCodeEnum.PARAM_ERR)
# 用户名 5-20个字符
if not re.match(r'^[a-zA-Z0-9_]{5,20}', username):
raise BusinessException(StatusCodeEnum.USER_ERR)
# 手机号合法性
if not mobile:
raise BusinessException(StatusCodeEnum.MOBILE_ERR)
return Response("成功", status=status.HTTP_200_OK)
2. 使用ExceptionHandler进行异常处理
除了使用中间件,我们还可以使用DRF内置的异常处理机制(ExceptionHandler)来处理API中的异常。
步骤1:自定义异常处理函数
首先,在utils/exceptions.py
文件中定义我们的自定义异常处理函数。
# utils/exceptions.py
from rest_framework.views import exception_handler
def custom_exception_handler(exc, context):
response = exception_handler(exc, context)
if response is not None:
response.data['status_code'] = response.status_code
elif isinstance(exc, Exception):
response = Response("其它异常")
return response
步骤2:配置ExceptionHandler
然后,在项目的settings.py
文件中配置我们自定义的异常处理函数。
# settings.py
REST_FRAMEWORK = {
# 统一异常处理
'EXCEPTION_HANDLER': 'utils.exception.custom_exception_handler'
}
这样,当API中发生异常时,就会调用我们自定义的异常处理函数,并返回统一的错误响应。
以上就是在Django Rest Framework中进行全局异常处理的两种方法。我们可以根据项目的具体需求选择合适的方法来实现异常处理。