error_handler.py 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. """
  2. 全局异常处理器
  3. 处理各类异常并返回统一格式的错误响应
  4. 需求: 7.3, 8.1, 8.2, 8.3, 8.4
  5. """
  6. import logging
  7. from fastapi import Request, FastAPI, HTTPException
  8. from fastapi.responses import JSONResponse
  9. from fastapi.exceptions import RequestValidationError
  10. from sqlalchemy.exc import SQLAlchemyError
  11. logging.basicConfig(
  12. level=logging.INFO,
  13. format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
  14. )
  15. logger = logging.getLogger(__name__)
  16. def register_exception_handlers(app: FastAPI):
  17. """注册全局异常处理器"""
  18. @app.exception_handler(HTTPException)
  19. async def http_exception_handler(request: Request, exc: HTTPException):
  20. """HTTP异常处理"""
  21. logger.warning(f"HTTP error {exc.status_code}: {exc.detail}")
  22. if isinstance(exc.detail, dict):
  23. payload = {"data": None}
  24. payload.update(exc.detail)
  25. else:
  26. payload = {
  27. "code": exc.status_code,
  28. "message": exc.detail,
  29. "detail": exc.detail,
  30. "data": None
  31. }
  32. return JSONResponse(
  33. status_code=exc.status_code,
  34. content=payload
  35. )
  36. @app.exception_handler(RequestValidationError)
  37. async def validation_exception_handler(request: Request, exc: RequestValidationError):
  38. """参数验证错误处理"""
  39. errors = exc.errors()
  40. logger.warning(f"Validation error: {errors}")
  41. # 提取第一条错误的友好提示,避免将原始列表暴露给前端
  42. if errors:
  43. first_error = errors[0]
  44. message = first_error.get("msg", "请求参数错误")
  45. # 去掉 Pydantic 自动添加的 "Value error, " 前缀
  46. if message.startswith("Value error, "):
  47. message = message[len("Value error, "):]
  48. else:
  49. message = "请求参数错误"
  50. return JSONResponse(
  51. status_code=400,
  52. content={"code": 400, "message": message, "data": None}
  53. )
  54. @app.exception_handler(SQLAlchemyError)
  55. async def database_exception_handler(request: Request, exc: SQLAlchemyError):
  56. """数据库错误处理"""
  57. logger.error(f"Database error: {exc}")
  58. return JSONResponse(
  59. status_code=500,
  60. content={"code": 500, "message": "Database error", "data": None}
  61. )
  62. @app.exception_handler(Exception)
  63. async def global_exception_handler(request: Request, exc: Exception):
  64. """全局异常处理"""
  65. logger.error(f"Unhandled exception: {exc}")
  66. return JSONResponse(
  67. status_code=500,
  68. content={"code": 500, "message": "Internal server error", "data": None}
  69. )