exceptions.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. # -*- coding: utf-8 -*-
  2. from typing import Any
  3. from fastapi import FastAPI, Request, status
  4. from fastapi.exceptions import RequestValidationError, ResponseValidationError
  5. from pydantic_validation_decorator import FieldValidationError
  6. from starlette.responses import JSONResponse
  7. from starlette.exceptions import HTTPException
  8. from sqlalchemy.exc import SQLAlchemyError
  9. from app.common.constant import RET
  10. from app.common.response import ErrorResponse
  11. from app.core.logger import log
  12. class CustomException(Exception):
  13. """
  14. 自定义异常基类
  15. """
  16. def __init__(
  17. self,
  18. msg: str = RET.EXCEPTION.msg,
  19. code: int = RET.EXCEPTION.code,
  20. status_code: int = status.HTTP_500_INTERNAL_SERVER_ERROR,
  21. data: Any | None = None,
  22. success: bool = False
  23. ) -> None:
  24. """
  25. 初始化异常对象。
  26. 参数:
  27. - msg (str): 错误消息。
  28. - code (int): 业务状态码。
  29. - status_code (int): HTTP 状态码。
  30. - data (Any | None): 附加数据。
  31. - success (bool): 是否成功标记,默认 False。
  32. 返回:
  33. - None
  34. """
  35. super().__init__(msg) # 调用父类初始化方法
  36. self.status_code = status_code
  37. self.code = code
  38. self.msg = msg
  39. self.data = data
  40. self.success = success
  41. def __str__(self) -> str:
  42. """返回异常消息
  43. 返回:
  44. - str: 异常消息
  45. """
  46. return self.msg
  47. def handle_exception(app: FastAPI):
  48. """
  49. 注册全局异常处理器。
  50. 参数:
  51. - app (FastAPI): 应用实例。
  52. 返回:
  53. - None
  54. """
  55. @app.exception_handler(CustomException)
  56. async def CustomExceptionHandler(request: Request, exc: CustomException) -> JSONResponse:
  57. """
  58. 自定义异常处理器
  59. 参数:
  60. - request (Request): 请求对象。
  61. - exc (CustomException): 自定义异常实例。
  62. 返回:
  63. - JSONResponse: 包含错误信息的 JSON 响应。
  64. """
  65. log.error(f"[自定义异常] {request.method} {request.url.path} | 错误码: {exc.code} | 错误信息: {exc.msg} | 详情: {exc.data}")
  66. return ErrorResponse(msg=exc.msg, code=exc.code, status_code=exc.status_code, data=exc.data)
  67. @app.exception_handler(HTTPException)
  68. async def HttpExceptionHandler(request: Request, exc: HTTPException) -> JSONResponse:
  69. """
  70. HTTP异常处理器
  71. 参数:
  72. - request (Request): 请求对象。
  73. - exc (HTTPException): HTTP异常实例。
  74. 返回:
  75. - JSONResponse: 包含错误信息的 JSON 响应。
  76. """
  77. log.error(f"[HTTP异常] {request.method} {request.url.path} | 状态码: {exc.status_code} | 错误信息: {exc.detail}")
  78. return ErrorResponse(msg=exc.detail, status_code=exc.status_code)
  79. @app.exception_handler(RequestValidationError)
  80. async def ValidationExceptionHandler(request: Request, exc: RequestValidationError) -> JSONResponse:
  81. """
  82. 请求参数验证异常处理器
  83. 参数:
  84. - request (Request): 请求对象。
  85. - exc (RequestValidationError): 请求参数验证异常实例。
  86. 返回:
  87. - JSONResponse: 包含错误信息的 JSON 响应。
  88. """
  89. error_mapping = {
  90. "Field required": "请求失败,缺少必填项!",
  91. "value is not a valid list": "类型错误,提交参数应该为列表!",
  92. "value is not a valid int": "类型错误,提交参数应该为整数!",
  93. "value could not be parsed to a boolean": "类型错误,提交参数应该为布尔值!",
  94. "Input should be a valid list": "类型错误,输入应该是一个有效的列表!"
  95. }
  96. raw_msg = exc.errors()[0].get('msg')
  97. msg = error_mapping.get(raw_msg, raw_msg)
  98. # 去掉Pydantic默认的前缀“Value error”, 仅保留具体提示内容
  99. if isinstance(msg, str) and msg.startswith("Value error"):
  100. if "," in msg:
  101. msg = msg.split(",", 1)[1].strip()
  102. else:
  103. msg = msg.replace("Value error", "").strip()
  104. log.error(f"[参数验证异常] {request.method} {request.url.path} | 错误信息: {msg} | 原始错误: {exc.errors()}")
  105. return ErrorResponse(msg=str(msg), status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, data=exc.body)
  106. @app.exception_handler(ResponseValidationError)
  107. async def ResponseValidationHandle(request: Request, exc: ResponseValidationError) -> JSONResponse:
  108. """
  109. 响应参数验证异常处理器
  110. 参数:
  111. - request (Request): 请求对象。
  112. - exc (ResponseValidationError): 响应参数验证异常实例。
  113. 返回:
  114. - JSONResponse: 包含错误信息的 JSON 响应。
  115. """
  116. log.error(f"[响应验证异常] {request.method} {request.url.path} | 错误信息: 响应数据格式错误 | 详情: {exc.errors()}")
  117. return ErrorResponse(msg="服务器响应格式错误", status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, data=exc.body)
  118. @app.exception_handler(SQLAlchemyError)
  119. async def SQLAlchemyExceptionHandler(request: Request, exc: SQLAlchemyError) -> JSONResponse:
  120. """
  121. 数据库异常处理器
  122. 参数:
  123. - request (Request): 请求对象。
  124. - exc (SQLAlchemyError): 数据库异常实例。
  125. 返回:
  126. - JSONResponse: 包含错误信息的 JSON 响应。
  127. """
  128. error_msg = '数据库操作失败'
  129. exc_type = type(exc).__name__
  130. # 对于生产环境,返回通用错误消息
  131. log.error(f"[数据库异常] {request.method} {request.url.path} | 错误类型: {exc_type} | 错误详情: {str(exc)}")
  132. return ErrorResponse(msg=f'{error_msg}: {exc_type}', status_code=status.HTTP_400_BAD_REQUEST, data=str(exc))
  133. @app.exception_handler(ValueError)
  134. async def ValueExceptionHandler(request: Request, exc: ValueError) -> JSONResponse:
  135. """
  136. 值异常处理器
  137. 参数:
  138. - request (Request): 请求对象。
  139. - exc (ValueError): 值异常实例。
  140. 返回:
  141. - JSONResponse: 包含错误信息的 JSON 响应。
  142. """
  143. log.error(f"[值异常] {request.method} {request.url.path} | 错误信息: {str(exc)}")
  144. return ErrorResponse(msg=str(exc), status_code=status.HTTP_400_BAD_REQUEST)
  145. @app.exception_handler(FieldValidationError)
  146. async def FieldValidationExceptionHandler(request: Request, exc: FieldValidationError) -> JSONResponse:
  147. """
  148. 字段验证异常处理器
  149. 参数:
  150. - request (Request): 请求对象。
  151. - exc (FieldValidationError): 字段验证异常实例。
  152. 返回:
  153. - JSONResponse: 包含错误信息的 JSON 响应。
  154. """
  155. log.error(f"[字段验证异常] {request.method} {request.url.path} | 错误信息: {exc.message}")
  156. return ErrorResponse(msg=exc.message, status_code=status.HTTP_422_UNPROCESSABLE_ENTITY)
  157. @app.exception_handler(Exception)
  158. async def AllExceptionHandler(request: Request, exc: Exception) -> JSONResponse:
  159. """
  160. 全局异常处理器
  161. 参数:
  162. - request (Request): 请求对象。
  163. - exc (Exception): 异常实例。
  164. 返回:
  165. - JSONResponse: 包含错误信息的 JSON 响应。
  166. """
  167. exc_type = type(exc).__name__
  168. log.error(f"[未捕获异常] {request.method} {request.url.path} | 错误类型: {exc_type} | 错误详情: {str(exc)}")
  169. # 对于未捕获的异常,返回通用错误信息
  170. return ErrorResponse(msg='服务器内部错误', status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, data=None)