From d63ce3326bc9a8721901f72161b580109fd0734a Mon Sep 17 00:00:00 2001 From: Azure <983547216@qq.com> Date: Tue, 23 Jun 2026 10:14:14 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20satoken=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/config/SaTokenConfigure.java | 3 +-- .../common/handler/GlobalExceptionHandler.java | 18 +++++++++++++++++- .../webgamebackend/sse/SseController.java | 5 ++++- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/webgame/webgamebackend/common/config/SaTokenConfigure.java b/src/main/java/com/webgame/webgamebackend/common/config/SaTokenConfigure.java index 5e51ab9..d7b5bd6 100644 --- a/src/main/java/com/webgame/webgamebackend/common/config/SaTokenConfigure.java +++ b/src/main/java/com/webgame/webgamebackend/common/config/SaTokenConfigure.java @@ -27,10 +27,9 @@ public class SaTokenConfigure implements WebMvcConfigurer { .notMatch("/v3/api-docs/**") .notMatch("/webjars/**") .notMatch("/error") - .notMatch("/sse/**") .check(r -> StpUtil.checkLogin()); })).addPathPatterns("/**") - .excludePathPatterns("/error", "/sse/**"); + .excludePathPatterns("/error"); } /** diff --git a/src/main/java/com/webgame/webgamebackend/common/handler/GlobalExceptionHandler.java b/src/main/java/com/webgame/webgamebackend/common/handler/GlobalExceptionHandler.java index a93fc03..d3295bc 100644 --- a/src/main/java/com/webgame/webgamebackend/common/handler/GlobalExceptionHandler.java +++ b/src/main/java/com/webgame/webgamebackend/common/handler/GlobalExceptionHandler.java @@ -12,16 +12,32 @@ import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.context.request.async.AsyncRequestTimeoutException; import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; import org.springframework.web.servlet.resource.NoResourceFoundException; /** - * 全局异常处理,统一返回 ApiResponse 格式 + * 全局异常处理,统一返回 ApiResponse JSON 格式。 + * + * SSE 端点的 401 由拦截器统一处理后返回 JSON,前端 fetch-event-source 通过 + * err.response.status 读取,不再需要服务端以 SSE 事件格式写错误。 */ @Slf4j @RestControllerAdvice public class GlobalExceptionHandler { + // ==================== SSE 异步超时 ==================== + + /** + * SSE 异步请求超时(SseEmitter timeout 到期的正常行为) + * + * 返回 void 避免 Spring 尝试写入已提交的响应导致二次异常。 + */ + @ExceptionHandler(AsyncRequestTimeoutException.class) + public void handleAsyncTimeout(AsyncRequestTimeoutException ex) { + // SSE 长连接超时是正常行为,无需记录日志 + } + // ==================== 业务异常 ==================== /** diff --git a/src/main/java/com/webgame/webgamebackend/sse/SseController.java b/src/main/java/com/webgame/webgamebackend/sse/SseController.java index 261861c..a8a6bf3 100644 --- a/src/main/java/com/webgame/webgamebackend/sse/SseController.java +++ b/src/main/java/com/webgame/webgamebackend/sse/SseController.java @@ -25,6 +25,9 @@ import java.util.concurrent.TimeUnit; * * 提供 GET /sse/subscribe 端点,建立持久化 SSE 连接。 * 连接成功后立即发送 connected 事件确认握手,之后每 30 秒发送心跳保活。 + * + * 鉴权由 SaTokenConfigure 拦截器统一处理,前端通过 fetch-event-source + * 的 headers 传 saToken,401 时由前端 err.response.status 直接读取。 */ @Slf4j @RestController @@ -37,7 +40,7 @@ public class SseController { /** * 建立 SSE 订阅连接 * - * 需要登录鉴权(Sa-Token 通过 Cookie 自动校验,EventSource 同域请求自动携带)。 + * 鉴权由拦截器处理,此处直接获取登录用户 ID。 * * @return SseEmitter 实例(30 分钟超时) */