from typing import Any from fastapi import HTTPException, Request, status from fastapi.exceptions import RequestValidationError from fastapi.responses import JSONResponse from sqlalchemy.exc import IntegrityError from app.core.exceptions import ( BusinessException, ExternalServiceException, ForbiddenException, NotFoundException, S2FException, UnauthorizedException, ValidationException, ) from app.core.logging import logger def create_error_response( code: str, message: str, details: Any = None, status_code: int = status.HTTP_500_INTERNAL_SERVER_ERROR, ) -> JSONResponse: """ 创建统一错误响应 Args: code: 错误代码 message: 错误消息 details: 错误详情 status_code: HTTP 状态码 Returns: JSON 响应 """ error_data = { "error": { "code": code, "message": message, } } if details: error_data["error"]["details"] = details return JSONResponse( status_code=status_code, content=error_data, ) async def s2f_exception_handler(request: Request, exc: S2FException) -> JSONResponse: """ 处理自定义业务异常 Args: request: 请求对象 exc: 异常对象 Returns: JSON 响应 """ logger.warning( "business_exception", code=exc.code, message=exc.message, details=exc.details, path=request.url.path, ) # 根据异常类型映射 HTTP 状态码 status_code_map = { NotFoundException: status.HTTP_404_NOT_FOUND, UnauthorizedException: status.HTTP_401_UNAUTHORIZED, ForbiddenException: status.HTTP_403_FORBIDDEN, ValidationException: status.HTTP_422_UNPROCESSABLE_ENTITY, BusinessException: status.HTTP_400_BAD_REQUEST, ExternalServiceException: status.HTTP_503_SERVICE_UNAVAILABLE, } status_code = status_code_map.get(type(exc), status.HTTP_500_INTERNAL_SERVER_ERROR) return create_error_response( code=exc.code, message=exc.message, details=exc.details, status_code=status_code, ) async def validation_exception_handler(request: Request, exc: RequestValidationError) -> JSONResponse: """ 处理请求验证异常 Args: request: 请求对象 exc: 验证异常 Returns: JSON 响应 """ logger.warning( "validation_error", errors=exc.errors(), body=exc.body, path=request.url.path, ) return create_error_response( code="VALIDATION_ERROR", message="请求参数验证失败", details={"errors": exc.errors()}, status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, ) async def http_exception_handler(request: Request, exc: HTTPException) -> JSONResponse: """ 处理 HTTP 异常 Args: request: 请求对象 exc: HTTP 异常 Returns: JSON 响应 """ logger.warning( "http_exception", status_code=exc.status_code, detail=exc.detail, path=request.url.path, ) return create_error_response( code="HTTP_ERROR", message=str(exc.detail), status_code=exc.status_code, ) async def integrity_error_handler(request: Request, exc: IntegrityError) -> JSONResponse: """ 处理数据库完整性错误 Args: request: 请求对象 exc: 完整性错误 Returns: JSON 响应 """ logger.error( "database_integrity_error", error=str(exc), path=request.url.path, ) return create_error_response( code="DATABASE_ERROR", message="数据库操作失败,可能存在重复或约束冲突", status_code=status.HTTP_409_CONFLICT, ) async def generic_exception_handler(request: Request, exc: Exception) -> JSONResponse: """ 处理未捕获的异常 Args: request: 请求对象 exc: 异常对象 Returns: JSON 响应 """ logger.error( "unhandled_exception", error=str(exc), error_type=type(exc).__name__, path=request.url.path, exc_info=True, ) return create_error_response( code="INTERNAL_ERROR", message="服务器内部错误", status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, )