Files
offerpai_python_ai/app/core/exceptions.py
T
2026-03-13 13:51:51 +08:00

74 lines
2.7 KiB
Python

import traceback
from fastapi import Request
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from starlette.exceptions import HTTPException as StarletteHTTPException
from app.config import settings
from app.core.logger import log
from app.core.schemas.responses import StandardResponse
# 友好的 HTTP 状态码消息映射
_FRIENDLY_MESSAGES = {
400: "请求参数错误",
401: "未经授权,请登录",
403: "权限不足,禁止访问",
404: "请求的资源不存在",
405: "请求方法不允许",
422: "数据验证失败",
429: "请求过于频繁",
500: "服务器内部错误",
}
def _get_uuid(request: Request) -> str | None:
return getattr(request.state, "uuid", None)
async def http_exception_handler(request: Request, exc: StarletteHTTPException) -> JSONResponse:
uuid = _get_uuid(request)
log.error(f"HTTPException -- uuid: {uuid} | status: {exc.status_code} | msg: {exc.detail}")
message = _FRIENDLY_MESSAGES.get(exc.status_code, str(exc.detail))
return JSONResponse(
status_code=exc.status_code,
content=StandardResponse.fail(msg=message, code=exc.status_code, uuid=uuid).model_dump(),
)
async def validation_exception_handler(request: Request, exc: RequestValidationError) -> JSONResponse:
uuid = _get_uuid(request)
errors = exc.errors()
log.error(f"ValidationError -- uuid: {uuid} | errors: {errors}")
return JSONResponse(
status_code=422,
content=StandardResponse.fail(msg="数据验证失败", code=422, data=errors, uuid=uuid).model_dump(),
)
async def assertion_error_handler(request: Request, exc: AssertionError) -> JSONResponse:
uuid = _get_uuid(request)
log.error(f"AssertionError -- uuid: {uuid} | msg: {exc}\n{traceback.format_exc()}")
return JSONResponse(
status_code=500,
content=StandardResponse.fail(msg=f"断言错误: {exc}", uuid=uuid).model_dump(),
)
async def global_exception_handler(request: Request, exc: Exception) -> JSONResponse:
uuid = _get_uuid(request)
log.error(f"Unhandled Exception -- uuid: {uuid} | msg: {exc}\n{traceback.format_exc()}")
msg = str(exc) if settings.env == "dev" else "服务器内部错误"
return JSONResponse(
status_code=500,
content=StandardResponse.fail(msg=msg, uuid=uuid).model_dump(),
)
def register_exception_handlers(app) -> None:
"""将异常处理器挂载到 FastAPI 应用"""
app.add_exception_handler(StarletteHTTPException, http_exception_handler)
app.add_exception_handler(RequestValidationError, validation_exception_handler)
app.add_exception_handler(AssertionError, assertion_error_handler)
app.add_exception_handler(Exception, global_exception_handler)