作者:玛丽 | 来源:互联网 | 2024-12-13 19:37
本文详细介绍如何结合Django框架和DRF(DjangoRESTFramework)来设计一套有效的全局异常处理系统。这套系统不仅能够妥善处理DRF引发的异常,还能兼容Django自带的admin界面异常处理逻辑。
本文旨在探讨如何有效地利用Django和DRF来构建一个全面的异常处理机制,确保应用程序在遇到错误时能够优雅地响应。我们将重点讨论如何保持Django admin的异常处理特性,同时增强DRF的异常处理能力。
目标设定
在没有DRF的情况下,仅需在Django中添加一个中间件即可实现全局异常处理。然而,DRF自带了异常处理功能,能自动处理某些异常并向客户端返回响应。因此,我们需要整合这两种异常处理方式,以达到以下目标:
- 保持Django admin的异常处理功能不变,以便于后台数据管理和调试。
- 捕捉并处理由DRF引发的异常,确保API的稳定性和用户体验。
- 处理除DRF异常外的其他Django异常,提供统一的错误响应格式。
DRF全局异常处理策略
DRF的异常处理主要依赖于APIException
类及其子类,这些异常通常由exception_handler
函数捕获和处理。此函数位于/python3.7/site-packages/rest_framework/views.py
中,负责处理APIException
、Http404
以及PermissionDenied
等异常,并将处理结果返回给前端。对于未被捕获的异常,该函数将返回None
,导致Django抛出500错误。
为了定制异常处理逻辑,我们可以在项目的设置文件中指定一个自定义的异常处理器:
REST_FRAMEWORK = { 'EXCEPTION_HANDLER': 'server.exception.exception_globe.globe_exception_handler' }
接下来,我们需要定义一个全局异常处理器,该处理器首先调用DRF的默认异常处理函数,然后根据需要调整响应内容,最后将未被DRF处理的异常交由Django处理:
def globe_exception_handler(exc, context): respOnse= exception_handler(exc, context) request = context['request'] if response is not None: if isinstance(response.data, list): msg = '; '.join(response.data) elif isinstance(response.data, str): msg = response.data else: msg = '发生了一个小错误 (* ̄︶ ̄)!' ex_data = { "msg": msg, "error_code": 1000, "request": request.path } return JsonResponse(data=ex_data, status=response.status_code) # 对于DRF无法处理的异常,返回给Django处理 return response
Django全局异常处理中间件
对于DRF未能处理的异常,我们可以利用Django的中间件机制来进行全局异常捕获。通过创建一个中间件,我们可以在请求处理过程中捕获任何未处理的异常,并以统一的格式返回给客户端。此外,为了不影响Django admin的功能,我们在中间件中特别处理了admin相关的URL请求。
try: from django.utils.deprecation import MiddlewareMixin # Django 1.10.x except ImportError: MiddlewareMixin = object # Django 1.4.x - Django 1.9.x class ExceptionGlobeMiddleware(MiddlewareMixin): def process_exception(self, request, exception): if str(request.path).startswith('/admin/'): return None ex_data = { "msg": "发生了一个小错误 (* ̄︶ ̄)!", "error_code": 1000, "request": request.path } return JsonResponse(data=ex_data, status=500)
通过这种方式,我们可以确保即使在非预期的错误发生时,也能向用户提供清晰、友好的错误信息,同时保持系统的稳定运行。