Files
aiagent/backend/app/core/error_handler.py

95 lines
2.9 KiB
Python
Raw Normal View History

2026-01-19 00:09:36 +08:00
"""
全局错误处理器
"""
import logging
import traceback
from fastapi import Request, status
from fastapi.responses import JSONResponse
from fastapi.exceptions import RequestValidationError
from sqlalchemy.exc import SQLAlchemyError
from app.core.exceptions import BaseAPIException
from app.core.config import settings
2026-01-19 00:09:36 +08:00
logger = logging.getLogger(__name__)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
"""处理验证错误"""
errors = []
for error in exc.errors():
field = ".".join(str(loc) for loc in error.get("loc", []))
errors.append({
"field": field,
"message": error.get("msg"),
"type": error.get("type")
})
logger.warning(f"验证错误: {errors}")
return JSONResponse(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
content={
"error": "VALIDATION_ERROR",
"message": "请求参数验证失败",
"details": errors
}
)
async def api_exception_handler(request: Request, exc: BaseAPIException):
"""处理自定义API异常"""
logger.error(f"API异常: {exc.detail} (错误码: {exc.error_code})")
return JSONResponse(
status_code=exc.status_code,
content={
"error": exc.error_code or "API_ERROR",
"message": exc.detail
}
)
async def sqlalchemy_exception_handler(request: Request, exc: SQLAlchemyError):
"""处理数据库错误"""
orig = getattr(exc, "orig", None)
detail = str(orig) if orig is not None else str(exc)
logger.error(f"数据库错误: {detail}", exc_info=True)
user_msg = "数据库操作失败,请稍后重试"
# MySQL 1054 / 常见 DDL 滞后:模型已增列但库未 alembic upgrade
if "Unknown column" in detail or "(1054," in detail or "1054" in detail:
user_msg = (
"数据库表结构与当前代码不一致(常见为缺少 executions 新列等)。"
"请在 backend 目录执行alembic upgrade head然后重启 API 与 Celery。"
)
payload: dict = {
"error": "DATABASE_ERROR",
"message": user_msg,
}
if settings.DEBUG:
payload["detail"] = detail[:4000]
2026-01-19 00:09:36 +08:00
return JSONResponse(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
content=payload,
2026-01-19 00:09:36 +08:00
)
async def general_exception_handler(request: Request, exc: Exception):
"""处理通用异常"""
logger.error(f"未处理的异常: {str(exc)}", exc_info=True)
logger.error(f"异常堆栈: {traceback.format_exc()}")
payload: dict = {
"error": "INTERNAL_ERROR",
"message": "服务器内部错误,请稍后重试",
}
if settings.DEBUG:
payload["detail"] = str(exc)[:4000]
2026-01-19 00:09:36 +08:00
return JSONResponse(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
content=payload,
2026-01-19 00:09:36 +08:00
)