""" 全局异常处理器 类似Java的@ControllerAdvice,统一处理所有异常 """ from fastapi import Request, status from fastapi.responses import JSONResponse from fastapi.exceptions import RequestValidationError from starlette.exceptions import HTTPException as StarletteHTTPException from app.core.exceptions import ( BaseAPIException, BusinessException, UnauthorizedException, ForbiddenException, NotFoundException, ValidationException, InternalServerException, StatusCode ) from app.utils.logger_utils import logger async def base_api_exception_handler(request: Request, exc: BaseAPIException) -> JSONResponse: """ 处理自定义API异常 返回统一的错误响应格式 """ logger.warning( f"API异常: {exc.detail} | " f"Status: {exc.status_code} | " f"Code: {exc.code} | " f"Path: {request.url.path}" ) return JSONResponse( status_code=exc.status_code, content={ "code": exc.code, "message": exc.detail, "data": None } ) async def http_exception_handler(request: Request, exc: StarletteHTTPException) -> JSONResponse: """ 处理FastAPI的HTTPException 转换为统一的响应格式 """ logger.warning( f"HTTP异常: {exc.detail} | " f"Status: {exc.status_code} | " f"Path: {request.url.path}" ) # 根据状态码确定错误码 error_code = exc.status_code if exc.status_code == 401: error_code = StatusCode.UNAUTHORIZED elif exc.status_code == 403: error_code = StatusCode.FORBIDDEN elif exc.status_code == 404: error_code = StatusCode.NOT_FOUND elif exc.status_code >= 500: error_code = StatusCode.INTERNAL_SERVER_ERROR return JSONResponse( status_code=exc.status_code, content={ "code": error_code, "message": exc.detail, "data": None } ) async def validation_exception_handler(request: Request, exc: RequestValidationError) -> JSONResponse: """ 处理请求参数验证异常 """ errors = exc.errors() error_messages = [] for error in errors: field = ".".join(str(loc) for loc in error.get("loc", [])) msg = error.get("msg", "参数验证失败") error_messages.append(f"{field}: {msg}") detail = "; ".join(error_messages) if error_messages else "参数验证失败" logger.warning( f"参数验证失败: {detail} | " f"Path: {request.url.path}" ) return JSONResponse( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, content={ "code": StatusCode.BAD_REQUEST, "message": detail, "data": None } ) async def general_exception_handler(request: Request, exc: Exception) -> JSONResponse: """ 处理所有未捕获的异常 这是最后的异常处理兜底 """ logger.error( f"未处理的异常: {str(exc)} | " f"Type: {type(exc).__name__} | " f"Path: {request.url.path}", exc_info=True ) # 检查异常消息中是否包含特定业务错误信息 error_message = str(exc) # 权限相关错误 if "无该货主权限" in error_message or "无权限" in error_message: return JSONResponse( status_code=403, content={ "code": StatusCode.FORBIDDEN, "message": error_message if error_message else "无该货主权限!", "data": None } ) # Token相关错误 if "登录已过期" in error_message or "token" in error_message.lower() or "登录" in error_message: return JSONResponse( status_code=401, content={ "code": StatusCode.INVALID_TOKEN, "message": error_message if error_message else "无效的登录信息", "data": None } ) # 资源不存在 if "不存在" in error_message or "not found" in error_message.lower(): return JSONResponse( status_code=404, content={ "code": StatusCode.NOT_FOUND, "message": error_message if error_message else "资源不存在", "data": None } ) # 默认返回500错误 return JSONResponse( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content={ "code": StatusCode.INTERNAL_SERVER_ERROR, "message": error_message if error_message else "服务器内部错误", "data": None } ) def register_exception_handlers(app): """ 注册所有异常处理器到FastAPI应用 """ # 自定义异常处理器(优先级最高) app.add_exception_handler(BaseAPIException, base_api_exception_handler) app.add_exception_handler(BusinessException, base_api_exception_handler) app.add_exception_handler(UnauthorizedException, base_api_exception_handler) app.add_exception_handler(ForbiddenException, base_api_exception_handler) app.add_exception_handler(NotFoundException, base_api_exception_handler) app.add_exception_handler(ValidationException, base_api_exception_handler) app.add_exception_handler(InternalServerException, base_api_exception_handler) # FastAPI的HTTPException app.add_exception_handler(StarletteHTTPException, http_exception_handler) # 请求验证异常 app.add_exception_handler(RequestValidationError, validation_exception_handler) # 通用异常处理器(兜底,必须最后注册) app.add_exception_handler(Exception, general_exception_handler)