fix: sse修改
This commit is contained in:
@@ -31,6 +31,7 @@ public class SaTokenConfigure implements WebMvcConfigurer {
|
|||||||
.notMatch("/v3/api-docs/**")
|
.notMatch("/v3/api-docs/**")
|
||||||
.notMatch("/webjars/**")
|
.notMatch("/webjars/**")
|
||||||
.notMatch("/error")
|
.notMatch("/error")
|
||||||
|
.notMatch("/sse/**")
|
||||||
.check(r -> StpUtil.checkLogin());
|
.check(r -> StpUtil.checkLogin());
|
||||||
})).addPathPatterns("/**")
|
})).addPathPatterns("/**")
|
||||||
.excludePathPatterns("/error");
|
.excludePathPatterns("/error");
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.webgame.webgamebackend.sse;
|
package com.webgame.webgamebackend.sse;
|
||||||
|
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
@@ -31,8 +32,26 @@ public class SseController {
|
|||||||
|
|
||||||
@GetMapping(value = "/subscribe", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
@GetMapping(value = "/subscribe", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
||||||
public SseEmitter subscribe(
|
public SseEmitter subscribe(
|
||||||
@RequestHeader(value = "Last-Event-ID", required = false) String lastEventId) {
|
@RequestHeader(value = "Last-Event-ID", required = false) String lastEventId,
|
||||||
String userId = StpUtil.getLoginIdAsString();
|
HttpServletResponse response) throws IOException {
|
||||||
|
|
||||||
|
// SSE 路径已排除在 SaInterceptor 之外,此处手动校验登录态
|
||||||
|
String token = StpUtil.getTokenValue();
|
||||||
|
if (token == null || token.isBlank()) {
|
||||||
|
log.warn("[SSE] 缺少认证 token");
|
||||||
|
return writeAuthError(response, HttpServletResponse.SC_UNAUTHORIZED, "缺少认证信息,请先登录");
|
||||||
|
}
|
||||||
|
|
||||||
|
Object loginId = StpUtil.getLoginIdByToken(token);
|
||||||
|
if (loginId == null) {
|
||||||
|
log.warn("[SSE] token 无效或已过期");
|
||||||
|
return writeAuthError(response, HttpServletResponse.SC_UNAUTHORIZED, "登录已过期,请重新登录");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置 Sa-Token 上下文,后续 StpUtil.getLoginIdAsString() 可用
|
||||||
|
StpUtil.setTokenValue(token, -1);
|
||||||
|
|
||||||
|
String userId = loginId.toString();
|
||||||
SseEmitter emitter = new SseEmitter(SSE_TIMEOUT_MS);
|
SseEmitter emitter = new SseEmitter(SSE_TIMEOUT_MS);
|
||||||
String connectionId = connectionManager.register(userId, emitter);
|
String connectionId = connectionManager.register(userId, emitter);
|
||||||
|
|
||||||
@@ -56,4 +75,21 @@ public class SseController {
|
|||||||
userId, connectionId, connectionManager.getOnlineCount());
|
userId, connectionId, connectionManager.getOnlineCount());
|
||||||
return emitter;
|
return emitter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向 SSE 客户端返回认证错误
|
||||||
|
*
|
||||||
|
* 直接写入 HttpServletResponse 返回 401 + SSE error 事件,
|
||||||
|
* 前端 SseClient.onopen 检测到 response.status === 401 后触发 onUnauthorized,
|
||||||
|
* 自动刷新 token 并重连。
|
||||||
|
*
|
||||||
|
* @return null,通知 Spring MVC 响应已处理完毕,无需 MessageConverter
|
||||||
|
*/
|
||||||
|
private SseEmitter writeAuthError(HttpServletResponse response, int status, String message) throws IOException {
|
||||||
|
response.setStatus(status);
|
||||||
|
response.setContentType(MediaType.TEXT_EVENT_STREAM_VALUE);
|
||||||
|
response.getWriter().write("event: error\ndata: {\"code\":" + status + ",\"message\":\"" + message + "\"}\n\n");
|
||||||
|
response.getWriter().flush();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user