Files
2026-06-04 10:55:23 +08:00

65 lines
2.3 KiB
Python

import logging
from fastapi import FastAPI, Request
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from sqlalchemy.exc import SQLAlchemyError
from app.core.exceptions import AppError
logger = logging.getLogger(__name__)
def register_exception_handlers(app: FastAPI) -> None:
"""异常注册:把业务异常转换为统一响应格式。"""
@app.exception_handler(AppError)
async def handle_app_error(request: Request, exc: AppError) -> JSONResponse:
logger.warning(
"business_error code=%s path=%s request_id=%s",
exc.code,
request.url.path,
request.headers.get("X-Request-Id"),
)
return JSONResponse(
status_code=exc.status_code,
content={"code": exc.code, "message": exc.message, "data": None},
)
@app.exception_handler(RequestValidationError)
async def handle_validation_error(request: Request, exc: RequestValidationError) -> JSONResponse:
logger.warning(
"validation_error path=%s request_id=%s errors=%s",
request.url.path,
request.headers.get("X-Request-Id"),
exc.errors(),
)
return JSONResponse(
status_code=422,
content={"code": "VALIDATION_ERROR", "message": "request validation failed", "data": {"errors": exc.errors()}},
)
@app.exception_handler(SQLAlchemyError)
async def handle_database_error(request: Request, exc: SQLAlchemyError) -> JSONResponse:
logger.exception(
"database_error path=%s request_id=%s",
request.url.path,
request.headers.get("X-Request-Id"),
)
return JSONResponse(
status_code=500,
content={"code": "DATABASE_ERROR", "message": "database operation failed", "data": None},
)
@app.exception_handler(Exception)
async def handle_unexpected_error(request: Request, exc: Exception) -> JSONResponse:
logger.exception(
"unexpected_error path=%s request_id=%s",
request.url.path,
request.headers.get("X-Request-Id"),
)
return JSONResponse(
status_code=500,
content={"code": "INTERNAL_ERROR", "message": "internal server error", "data": None},
)