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

Python实现方法全局自动捕获异常,避免Web服务器停止

解决方案:全局异常捕获与日志记录

嘿,这个需求其实挺常见的,而且你之前对装饰器的理解有点小偏差哦——装饰器可不只是在方法执行前跑代码,它能完全包裹住目标方法的整个执行流程,包括捕获异常!这正好能解决你的问题,不用逐个修改现有方法,就能实现全局异常捕获、日志记录,还能让服务器一直跑下去。

一、先纠正装饰器的认知误区

装饰器本质是一个包装函数,它可以把目标方法的执行逻辑完全包裹起来:既可以在方法执行前做准备,也能在执行后做收尾,更关键的是——它能捕获方法执行过程中抛出的所有异常,完美匹配你的需求。

二、实现通用的异常捕获装饰器

先写一个通用的装饰器,它会帮你完成:捕获异常、写入日志文件、保证应用不崩溃这三件事。示例代码如下:

import logging
from functools import wraps

# 配置日志:将错误信息写入server_errors.log文件
logging.basicConfig(
    filename='server_errors.log',
    level=logging.ERROR,
    format='%(asctime)s - %(funcName)s - %(levelname)s - %(message)s'
)

def catch_and_log_exceptions(func):
    @wraps(func)  # 保留原函数的元信息(比如函数名)
    def wrapper(*args, **kwargs):
        try:
            # 执行原方法
            return func(*args, **kwargs)
        except Exception as e:
            # 记录异常日志,包含堆栈信息(方便排查问题)
            logging.error(f"异常详情:{str(e)}", exc_info=True)
            # 如果是Web接口方法,这里可以返回友好的错误响应(比如JSON)
            # 比如return {"error": "服务器内部错误"}, 500
            return None  # 根据你的业务需求调整返回值
    return wrapper

三、批量应用装饰器到所有方法

不用逐个手动给方法加装饰器,有两种高效的方式:

1. 自动装饰类的所有方法

如果你的plus、by等方法都在同一个类里,可以写一个工具装饰器,自动给类内所有方法加上异常捕获:

def decorate_all_methods(decorator):
    def decorate(cls):
        # 遍历类的所有属性,给可调用的方法加上装饰器
        for attr_name, attr_value in vars(cls).items():
            if callable(attr_value):
                setattr(cls, attr_name, decorator(attr_value))
        return cls
    return decorate

# 给你的Web服务器类加上这个装饰器,所有方法自动获得异常捕获能力
@decorate_all_methods(catch_and_log_exceptions)
class WebServer:
    def plus(self, a, b):
        return a + b
    
    def by(self, a, b):
        if b == 0:
            raise ValueError("除数不能为0")
        return a / b
    
    def split(self, s, sep):
        return s.split(sep)
    
    def takeaway(self, a, b):
        return a - b

2. 手动批量装饰(适合零散方法)

如果你的方法不在同一个类里,也可以手动批量给它们加装饰器:

# 假设你的方法是独立函数
def plus(a, b):
    return a + b

def by(a, b):
    if b == 0:
        raise ValueError("除数不能为0")
    return a / b

# 批量应用装饰器
plus = catch_and_log_exceptions(plus)
by = catch_and_log_exceptions(by)
split = catch_and_log_exceptions(split)
takeaway = catch_and_log_exceptions(takeaway)

四、如果是基于Web框架的服务器(比如Flask/Django)

如果你的Web服务器是用Flask、Django这类框架开发的,还有更优雅的全局方案——用框架自带的全局异常处理中间件:

Flask示例

from flask import Flask, jsonify

app = Flask(__name__)

# 全局异常捕获处理器
@app.errorhandler(Exception)
def handle_all_exceptions(e):
    logging.error(f"未处理异常:{str(e)}", exc_info=True)
    return jsonify({"error": "服务器内部错误"}), 500

# 你的路由方法(无需手动加装饰器)
@app.route('/plus/<int:a>/<int:b>')
def plus(a, b):
    return str(a + b)

@app.route('/by/<int:a>/<int:b>')
def by(a, b):
    return str(a / b)

Django示例

自定义全局异常中间件,然后在settings.py中配置:

# 自定义中间件文件 middleware.py
import logging
from django.http import JsonResponse

class GlobalExceptionMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        try:
            response = self.get_response(request)
        except Exception as e:
            logging.error(f"未处理异常:{str(e)}", exc_info=True)
            return JsonResponse({"error": "服务器内部错误"}, status=500)
        return response

# 在settings.py的MIDDLEWARE列表中添加这个中间件
MIDDLEWARE = [
    # 其他中间件...
    'your_app.middleware.GlobalExceptionMiddleware',
]

五、关键注意事项

  • 日志一定要记录异常堆栈信息(也就是代码里的exc_info=True),不然你只知道报错了,却不知道错在哪一行,很难排查。
  • 不要捕获KeyboardInterrupt这类终止程序的信号,否则你可能没法正常关闭服务器。
  • 如果是Web接口,捕获异常后要返回合适的HTTP状态码(比如500),避免客户端一直处于等待状态。

这样一来,不管你的哪个方法抛出异常,都会被全局捕获,错误日志会写入文件,服务器也能继续运行,完全不用逐个修改现有方法~

内容的提问来源于stack exchange,提问作者Máxima Alekz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 10:29:33