| 
									
										
										
										
											2025-09-02 18:51:50 +08:00
										 |  |  |  | from fastapi import Request, status | 
					
						
							|  |  |  |  | from fastapi.responses import JSONResponse | 
					
						
							|  |  |  |  | from fastapi.exceptions import HTTPException, RequestValidationError | 
					
						
							|  |  |  |  | from mysql.connector import Error as MySQLError | 
					
						
							|  |  |  |  | from jose import JWTError | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | from schema.response_schema import APIResponse | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | async def global_exception_handler(request: Request, exc: Exception): | 
					
						
							| 
									
										
										
										
											2025-09-08 17:34:23 +08:00
										 |  |  |  |     """全局异常处理器: 所有未捕获的异常都会在这里统一处理""" | 
					
						
							| 
									
										
										
										
											2025-09-02 18:51:50 +08:00
										 |  |  |  |     # 1. 请求参数验证错误(Pydantic 校验失败) | 
					
						
							|  |  |  |  |     if isinstance(exc, RequestValidationError): | 
					
						
							|  |  |  |  |         error_details = [] | 
					
						
							|  |  |  |  |         for err in exc.errors(): | 
					
						
							|  |  |  |  |             error_details.append(f"{err['loc'][1]}: {err['msg']}") | 
					
						
							|  |  |  |  |         return JSONResponse( | 
					
						
							|  |  |  |  |             status_code=status.HTTP_400_BAD_REQUEST, | 
					
						
							|  |  |  |  |             content=APIResponse( | 
					
						
							|  |  |  |  |                 code=400, | 
					
						
							| 
									
										
										
										
											2025-09-08 17:34:23 +08:00
										 |  |  |  |                 message=f"请求参数错误: {'; '.join(error_details)}", | 
					
						
							| 
									
										
										
										
											2025-09-02 18:51:50 +08:00
										 |  |  |  |                 data=None | 
					
						
							|  |  |  |  |             ).model_dump() | 
					
						
							|  |  |  |  |         ) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     # 2. HTTP 异常(主动抛出的业务错误、如 401/404) | 
					
						
							|  |  |  |  |     if isinstance(exc, HTTPException): | 
					
						
							|  |  |  |  |         return JSONResponse( | 
					
						
							|  |  |  |  |             status_code=exc.status_code, | 
					
						
							|  |  |  |  |             content=APIResponse( | 
					
						
							|  |  |  |  |                 code=exc.status_code, | 
					
						
							|  |  |  |  |                 message=exc.detail, | 
					
						
							|  |  |  |  |                 data=None | 
					
						
							|  |  |  |  |             ).model_dump() | 
					
						
							|  |  |  |  |         ) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     # 3. JWT 相关错误(Token 无效/过期) | 
					
						
							|  |  |  |  |     if isinstance(exc, JWTError): | 
					
						
							|  |  |  |  |         return JSONResponse( | 
					
						
							|  |  |  |  |             status_code=status.HTTP_401_UNAUTHORIZED, | 
					
						
							|  |  |  |  |             content=APIResponse( | 
					
						
							|  |  |  |  |                 code=401, | 
					
						
							|  |  |  |  |                 message="Token 无效或已过期", | 
					
						
							|  |  |  |  |                 data=None | 
					
						
							|  |  |  |  |             ).model_dump(), | 
					
						
							|  |  |  |  |             headers={"WWW-Authenticate": "Bearer"}, | 
					
						
							|  |  |  |  |         ) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     # 4. MySQL 数据库错误 | 
					
						
							|  |  |  |  |     if isinstance(exc, MySQLError): | 
					
						
							|  |  |  |  |         return JSONResponse( | 
					
						
							|  |  |  |  |             status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, | 
					
						
							|  |  |  |  |             content=APIResponse( | 
					
						
							|  |  |  |  |                 code=500, | 
					
						
							| 
									
										
										
										
											2025-09-08 17:34:23 +08:00
										 |  |  |  |                 message=f"数据库错误: {str(exc)}", | 
					
						
							| 
									
										
										
										
											2025-09-02 18:51:50 +08:00
										 |  |  |  |                 data=None | 
					
						
							|  |  |  |  |             ).model_dump() | 
					
						
							|  |  |  |  |         ) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     # 5. 其他未知错误(兜底处理) | 
					
						
							|  |  |  |  |     return JSONResponse( | 
					
						
							|  |  |  |  |         status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, | 
					
						
							|  |  |  |  |         content=APIResponse( | 
					
						
							|  |  |  |  |             code=500, | 
					
						
							| 
									
										
										
										
											2025-09-08 17:34:23 +08:00
										 |  |  |  |             message=f"服务器内部错误: {str(exc)}", | 
					
						
							| 
									
										
										
										
											2025-09-02 18:51:50 +08:00
										 |  |  |  |             data=None | 
					
						
							|  |  |  |  |         ).model_dump() | 
					
						
							|  |  |  |  |     ) |