exception_handlers.py 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. """全局异常处理:统一响应 {success, message, error_code}。"""
  2. from __future__ import annotations
  3. from fastapi import FastAPI, Request
  4. from fastapi.exceptions import RequestValidationError
  5. from fastapi.responses import JSONResponse
  6. from starlette.exceptions import HTTPException as StarletteHTTPException
  7. from ..exceptions import AppError
  8. from ..utils.logger import get_logger
  9. logger = get_logger("app.errors")
  10. def _body(message: str, error_code: str) -> dict:
  11. return {"success": False, "message": message, "error_code": error_code}
  12. def register_exception_handlers(app: FastAPI) -> None:
  13. @app.exception_handler(AppError)
  14. async def app_error_handler(_: Request, exc: AppError) -> JSONResponse:
  15. logger.warning("[%s] %s", exc.code, exc.message)
  16. return JSONResponse(
  17. status_code=exc.status_code,
  18. content=_body(exc.message, exc.code),
  19. )
  20. @app.exception_handler(RequestValidationError)
  21. async def validation_handler(_: Request, exc: RequestValidationError) -> JSONResponse:
  22. msg = "; ".join(
  23. f"{'.'.join(str(x) for x in err.get('loc', ()))}: {err.get('msg')}"
  24. for err in exc.errors()
  25. )
  26. logger.warning("validation: %s", msg)
  27. return JSONResponse(status_code=422, content=_body(msg, "VALIDATION_ERROR"))
  28. @app.exception_handler(StarletteHTTPException)
  29. async def http_exception_handler(_: Request, exc: StarletteHTTPException) -> JSONResponse:
  30. detail = exc.detail
  31. message = detail if isinstance(detail, str) else str(detail)
  32. return JSONResponse(
  33. status_code=exc.status_code,
  34. content=_body(message, "HTTP_ERROR"),
  35. )
  36. @app.exception_handler(Exception)
  37. async def unhandled_handler(_: Request, exc: Exception) -> JSONResponse:
  38. logger.exception("unhandled: %s", exc)
  39. return JSONResponse(
  40. status_code=500,
  41. content=_body("服务器内部错误", "INTERNAL_ERROR"),
  42. )