Django中如何实现返回503且不发送管理员邮件的自定义异常
实现方案
核心逻辑为不主动在中间件吃掉异常导致异常栈丢失,通过「自定义带标记的异常类 + 异常状态码内置 + 邮件告警过滤」的组合同时满足两个需求:
步骤1:定义自定义异常类
根据你的项目类型选择对应的异常基类,同时添加跳过告警邮件的标记:
DRF项目场景
from rest_framework.exceptions import APIException class ServiceUnavailableException(APIException): # 直接指定返回状态码为503 status_code = 503 default_detail = "服务暂时不可用,请稍后重试" default_code = "service_unavailable" # 自定义标记,方便告警过滤(双重保险) skip_admin_email = True
普通Django项目场景
from django.http import JsonResponse class ServiceUnavailableException(JsonResponse): status_code = 503 skip_admin_email = True def __init__(self, *args, **kwargs): super().__init__({"detail": "Error try later"}, *args, **kwargs)
步骤2:移除原中间件的异常返回逻辑
不需要再用中间件捕获该异常返回响应,直接在业务代码需要触发503的位置抛出ServiceUnavailableException即可:
- DRF项目抛出后会自动按异常配置返回503响应
- 普通Django项目抛出该异常后,Django会自动将其作为响应返回,状态码为503
步骤3:调整自定义告警邮件处理器逻辑
因为不再吃掉异常,异常栈exc_info会完整保留在日志记录中,直接在邮件发送前做类型/标记过滤即可:
from django.utils.log import AdminEmailHandler class CustomAdminEmailHandler(AdminEmailHandler): def emit(self, record): exc_info = record.exc_info if not exc_info: super().emit(record) return exc_type, exc_instance, _ = exc_info # 匹配到自定义异常就跳过邮件发送 if issubclass(exc_type, ServiceUnavailableException) or getattr(exc_instance, 'skip_admin_email', False): return super().emit(record)
原问题原因说明
之前你在中间件的process_exception方法中直接返回了JsonResponse,Django会判定该异常已被处理完成,不会再将异常栈记录到日志中,导致邮件处理器无法获取异常类型做过滤。本次方案让异常自然抛出,既保留了完整异常栈用于过滤,又内置了503状态码的返回规则,同时满足两个需求。
内容的提问来源于stack exchange,提问作者Def Soudani
相关产品推荐
相关产品推荐

