You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 21:48:04