diff --git a/backend-single/src/main/java/com/emotion/exception/GlobalExceptionHandler.java b/backend-single/src/main/java/com/emotion/exception/GlobalExceptionHandler.java index 13da8bd..a301086 100644 --- a/backend-single/src/main/java/com/emotion/exception/GlobalExceptionHandler.java +++ b/backend-single/src/main/java/com/emotion/exception/GlobalExceptionHandler.java @@ -72,6 +72,45 @@ public class GlobalExceptionHandler { } } + /** + * 处理微信 API 异常(业务错误 400 / 内部错误 500 / 上游错误 502) + * + *

根据异常内部 code 映射到不同友好提示(不直接暴露原始异常消息给前端): + *

+ * + *

详细异常消息仅记录到日志(含 [WeChatAPI] 前缀),前端仅看到友好提示。 + */ + @ExceptionHandler(WechatApiException.class) + public Result handleWechatApiException(WechatApiException e, HttpServletRequest request) { + String userMessage; + switch (e.getCode()) { + case 400: + userMessage = "微信授权失败,请重试"; + log.warn("[WeChatAPI] 微信授权失败,code={}, method={}, uri={}, detail={}", + e.getCode(), request.getMethod(), request.getRequestURI(), e.getMessage()); + return Result.badRequest(userMessage); + case 500: + userMessage = "微信登录失败,请重试"; + log.warn("[WeChatAPI] 微信登录内部错误,code={}, method={}, uri={}, detail={}", + e.getCode(), request.getMethod(), request.getRequestURI(), e.getMessage()); + return Result.error(userMessage); + case 502: + userMessage = "微信服务暂不可用,请稍后重试"; + log.warn("[WeChatAPI] 微信服务上游错误,code={}, method={}, uri={}, detail={}", + e.getCode(), request.getMethod(), request.getRequestURI(), e.getMessage()); + return Result.error(e.getCode(), userMessage); + default: + userMessage = "微信登录异常,请重试"; + log.warn("[WeChatAPI] 微信登录未知错误,code={}, method={}, uri={}, detail={}", + e.getCode(), request.getMethod(), request.getRequestURI(), e.getMessage()); + return Result.error(userMessage); + } + } + /** * 处理参数校验异常 */ diff --git a/backend-single/src/test/java/com/emotion/exception/GlobalExceptionHandlerWechatTest.java b/backend-single/src/test/java/com/emotion/exception/GlobalExceptionHandlerWechatTest.java new file mode 100644 index 0000000..815fc3a --- /dev/null +++ b/backend-single/src/test/java/com/emotion/exception/GlobalExceptionHandlerWechatTest.java @@ -0,0 +1,72 @@ +package com.emotion.exception; + +import com.emotion.common.Result; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.mock.web.MockHttpServletRequest; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * GlobalExceptionHandler 的 WechatApiException handler 单元测试 + * + * 验证: + * 1. 400 业务错误 → "微信授权失败,请重试" + * 2. 500 内部错误 → "微信登录失败,请重试" + * 3. 502 上游错误 → "微信服务暂不可用,请稍后重试" + */ +@ExtendWith(MockitoExtension.class) +class GlobalExceptionHandlerWechatTest { + + @InjectMocks + private GlobalExceptionHandler handler; + + private MockHttpServletRequest request; + + @BeforeEach + void setUp() { + request = new MockHttpServletRequest(); + request.setMethod("POST"); + request.setRequestURI("/api/wechat/login"); + } + + @Test + void handleWechatApiException_Code400_ReturnsBadRequestWithFriendlyMessage() { + WechatApiException ex = new WechatApiException(400, "errcode=40029, errmsg=invalid code (internal detail)", ""); + + Result result = handler.handleWechatApiException(ex, request); + + assertNotNull(result); + assertEquals("微信授权失败,请重试", result.getMessage()); + // Ensure internal detail is NOT exposed to frontend + assertFalse(result.getMessage().contains("errcode")); + assertFalse(result.getMessage().contains("40029")); + } + + @Test + void handleWechatApiException_Code500_ReturnsInternalErrorWithFriendlyMessage() { + WechatApiException ex = new WechatApiException(500, "JSON parse failure at line 1 (internal detail)", ""); + + Result result = handler.handleWechatApiException(ex, request); + + assertNotNull(result); + assertEquals("微信登录失败,请重试", result.getMessage()); + assertFalse(result.getMessage().contains("JSON")); + assertFalse(result.getMessage().contains("parse")); + } + + @Test + void handleWechatApiException_Code502_ReturnsBadGatewayWithFriendlyMessage() { + WechatApiException ex = new WechatApiException(502, "Connection refused: api.weixin.qq.com (internal detail)", ""); + + Result result = handler.handleWechatApiException(ex, request); + + assertNotNull(result); + assertEquals("微信服务暂不可用,请稍后重试", result.getMessage()); + assertFalse(result.getMessage().contains("Connection")); + assertFalse(result.getMessage().contains("refused")); + } +}