在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.codeself.errmsg = enum_cls.errmsgself.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 = Noneself.errmsg = Noneself._data = dict()@staticmethoddef ok():"""組織成功響應信息:return:"""r = R()r.code = StatusCodeEnum.OK.coder.errmsg = StatusCodeEnum.OK.errmsgreturn r@staticmethoddef error():"""組織錯誤響應信息:return:"""r = R()r.code = StatusCodeEnum.ERROR.coder.errmsg = StatusCodeEnum.ERROR.errmsgreturn r@staticmethoddef server_error():"""組織服務器錯誤信息:return:"""r = R()r.code = StatusCodeEnum.SERVER_ERR.coder.errmsg = StatusCodeEnum.SERVER_ERR.errmsgreturn r@staticmethoddef set_result(enum):"""組織對應枚舉類的響應信息:param enum: 狀態枚舉類:return:"""r = R()r.code = enum.coder.errmsg = enum.errmsgreturn rdef data(self, key=None, obj=None):"""統一后端返回的數據"""if key:self._data[key] = objcontext = {'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_codeelif 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中進行全局異常處理的兩種方法。我們可以根據項目的具體需求選擇合適的方法來實現異常處理。