abfc598d3f
1. 删除无用文件: - apps/api/app/core/database.py (未被引用的死代码) - requirements-quality.txt (与 requirements-dev.txt 完全重复) - fix_script.py, fix_tracker_encoding.py (一次性修复脚本) - init_tracker_phase4.py, init_tracker_simple.py, update_tracker.py (SQLite迁移脚本) 2. 清理死代码: - apps/api/app/db.py: 移除未使用的 get_db() 函数和 sqlalchemy.orm 导入 - 11个路由/中间件文件: 移除未使用的 import (os, datetime, BaseModel, Session, List 等) 3. 消除重复定义: - apps/worker/video_processing/video_compose_service.py: 移除重复的 EditingMode 枚举 - 改为从 packages.domain.editing_mode 导入统一的 EditingMode 影响: 无功能变更,仅移除未使用的代码
139 lines
3.6 KiB
Python
139 lines
3.6 KiB
Python
"""
|
|
全局异常处理和错误响应
|
|
"""
|
|
|
|
import logging
|
|
|
|
from fastapi import Request, status
|
|
from fastapi.exceptions import RequestValidationError
|
|
from fastapi.responses import JSONResponse
|
|
from starlette.exceptions import HTTPException as StarletteHTTPException
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class APIException(Exception):
|
|
"""API 异常基类"""
|
|
|
|
def __init__(
|
|
self,
|
|
message: str,
|
|
status_code: int = status.HTTP_400_BAD_REQUEST,
|
|
error_code: str = "API_ERROR",
|
|
):
|
|
self.message = message
|
|
self.status_code = status_code
|
|
self.error_code = error_code
|
|
super().__init__(message)
|
|
|
|
|
|
class AuthenticationError(APIException):
|
|
"""认证错误"""
|
|
|
|
def __init__(self, message: str = "Authentication failed"):
|
|
super().__init__(
|
|
message=message,
|
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
error_code="AUTH_ERROR",
|
|
)
|
|
|
|
|
|
class PermissionDeniedError(APIException):
|
|
"""权限拒绝"""
|
|
|
|
def __init__(self, message: str = "Permission denied"):
|
|
super().__init__(
|
|
message=message,
|
|
status_code=status.HTTP_403_FORBIDDEN,
|
|
error_code="PERMISSION_DENIED",
|
|
)
|
|
|
|
|
|
class ResourceNotFoundError(APIException):
|
|
"""资源不存在"""
|
|
|
|
def __init__(self, resource: str = "Resource"):
|
|
super().__init__(
|
|
message=f"{resource} not found",
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
error_code="NOT_FOUND",
|
|
)
|
|
|
|
|
|
class ValidationError(APIException):
|
|
"""验证错误"""
|
|
|
|
def __init__(self, message: str):
|
|
super().__init__(
|
|
message=message,
|
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
error_code="VALIDATION_ERROR",
|
|
)
|
|
|
|
|
|
async def api_exception_handler(request: Request, exc: APIException):
|
|
"""API 异常处理"""
|
|
return JSONResponse(
|
|
status_code=exc.status_code,
|
|
content={
|
|
"error": {
|
|
"code": exc.error_code,
|
|
"message": exc.message,
|
|
}
|
|
},
|
|
)
|
|
|
|
|
|
async def http_exception_handler(request: Request, exc: StarletteHTTPException):
|
|
"""HTTP 异常处理"""
|
|
return JSONResponse(
|
|
status_code=exc.status_code,
|
|
content={
|
|
"error": {
|
|
"code": f"HTTP_{exc.status_code}",
|
|
"message": exc.detail,
|
|
}
|
|
},
|
|
)
|
|
|
|
|
|
async def validation_exception_handler(request: Request, exc: RequestValidationError):
|
|
"""请求验证异常处理"""
|
|
errors = []
|
|
for error in exc.errors():
|
|
errors.append(
|
|
{
|
|
"field": ".".join(str(loc) for loc in error["loc"]),
|
|
"message": error["msg"],
|
|
"type": error["type"],
|
|
}
|
|
)
|
|
|
|
return JSONResponse(
|
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
content={
|
|
"error": {
|
|
"code": "VALIDATION_ERROR",
|
|
"message": "Request validation failed",
|
|
"details": errors,
|
|
}
|
|
},
|
|
)
|
|
|
|
|
|
async def general_exception_handler(request: Request, exc: Exception):
|
|
"""通用异常处理"""
|
|
logger.error(f"Unhandled exception: {exc}", exc_info=True)
|
|
|
|
# 生产环境不返回详细错误信息
|
|
return JSONResponse(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
content={
|
|
"error": {
|
|
"code": "INTERNAL_ERROR",
|
|
"message": "An internal error occurred",
|
|
# "detail": str(exc), # 仅在开发环境启用
|
|
}
|
|
},
|
|
)
|