ForcePilot/backend/server/utils/error_handlers.py
Kris 12ec5af0de feat: 新增全链路追踪、优雅关停支持与统一异常处理,优化渠道查询接口
1. 新增TraceId中间件实现全链路请求追踪
2. 新增在途请求计数器与中间件支持优雅关停
3. 重构全局异常处理器,统一三模块异常响应格式
4. 优化渠道查询接口,新增多维度过滤与模糊匹配
5. 重构channels模块数据库会话管理,避免事务冲突
6. 新增目录搜索建议与目录导出功能
2026-07-07 16:25:47 +08:00

93 lines
3.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""全局异常处理器集中实现。
3 个 handler
- unified_error_handler处理三模块异常满足 UnifiedError 协议)
- request_validation_error_handler处理 Pydantic 请求体校验失败
- unhandled_exception_handler兜底原生 Exception
"""
from __future__ import annotations
import logging
from fastapi import Request
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from yuxi.channels.contract.errors import Error as ChannelError
from yuxi.external_systems.exceptions import ExternalSystemError
from yuxi.scheduler.exceptions import SchedulerError
from server.utils.error_response import build_error_response, build_error_response_from_exc
async def unified_error_handler(
_request: Request,
exc: ChannelError | ExternalSystemError | SchedulerError,
) -> JSONResponse:
"""三模块异常统一处理器。
三模块异常基类都满足 UnifiedError 协议status_code/error_code/message/
details/trace_id通过 build_error_response_from_exc() 统一构建响应。
不再有 isinstance 特判,不再有查表/类属性分支,逻辑完全相同。
Args:
_request: FastAPI 请求对象(未使用)。
exc: 三模块异常之一。
Returns:
统一格式的错误响应。
"""
return build_error_response_from_exc(exc)
async def unhandled_exception_handler(_request: Request, exc: Exception) -> JSONResponse:
"""原生异常兜底处理器。
所有未被特定异常处理器捕获的 Exception 在此统一兜底,
返回结构化 500 响应。trace_id 自动从 ContextVar 获取。
Args:
_request: FastAPI 请求对象(未使用)。
exc: 未被捕获的原生异常。
Returns:
500 内部服务器错误响应。
"""
logging.getLogger("uvicorn.error").exception("unhandled exception", exc_info=exc)
return build_error_response(
status_code=500,
code="INTERNAL",
message="Internal server error",
)
async def request_validation_error_handler(
_request: Request,
exc: RequestValidationError,
) -> JSONResponse:
"""Pydantic 请求体校验失败统一处理器。
将 FastAPI 默认的 422 + ``{"detail": [...]}`` 转换为项目统一格式
422 + ``{"success": false, "error": {...}}``,确保响应格式一致。
Pydantic v2 的 ``model_validator`` / ``field_validator`` 中抛出的
``ValueError`` 子类(含项目的 ``ValidationError``)会被包装为
``pydantic.ValidationError``,再由 FastAPI 转为 ``RequestValidationError``
本处理器统一捕获并转换为项目格式。状态码保持 422FastAPI 标准),
仅统一响应结构。
"""
errors = exc.errors()
first = errors[0] if errors else {}
loc = first.get("loc", [])
field = ".".join(str(part) for part in loc) if loc else ""
message = first.get("msg", "request validation failed")
# Pydantic 对 ValueError 子类的包装会加 "Value error, " 前缀,去除以还原原始 message
if message.startswith("Value error, "):
message = message[len("Value error, ") :]
return build_error_response(
status_code=422,
code="VALIDATION_ERROR",
message=message,
details={"field": field, "errors": errors},
)