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 映射到不同友好提示(不直接暴露原始异常消息给前端):
+ *
+ * - 400 - 微信业务错误(如 errcode 40029 invalid code):"微信授权失败,请重试"
+ * - 500 - 内部 JSON 解析失败:"微信登录失败,请重试"
+ * - 502 - 网络异常 / 非 2xx / Content-Type 不是 JSON:"微信服务暂不可用,请稍后重试"
+ *
+ *
+ * 详细异常消息仅记录到日志(含 [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"));
+ }
+}