fix 修复 push 模块 sse/ws 浏览器多标签页互挤掉线问题

This commit is contained in:
疯狂的狮子Li
2026-06-25 17:23:44 +08:00
parent e8b033c4ef
commit eab4228548
3 changed files with 35 additions and 0 deletions
@@ -31,4 +31,9 @@ public interface MessageConstants {
* 心跳响应标识 * 心跳响应标识
*/ */
String PONG = "pong"; String PONG = "pong";
/**
* 同一 token 的新连接替换旧连接时发送给旧连接的控制消息。
*/
String KICKED = "kicked";
} }
@@ -65,6 +65,7 @@ public class SseEmitterSessionManager implements PushSessionManager {
// 关闭已存在的SseEmitter,防止超过最大连接数 // 关闭已存在的SseEmitter,防止超过最大连接数
SseEmitter oldEmitter = emitters.remove(token); SseEmitter oldEmitter = emitters.remove(token);
if (oldEmitter != null) { if (oldEmitter != null) {
sendKickedMessage(oldEmitter);
oldEmitter.complete(); oldEmitter.complete();
} }
@@ -103,6 +104,21 @@ public class SseEmitterSessionManager implements PushSessionManager {
return emitter; return emitter;
} }
/**
* 通知旧连接已被同 token 新连接替换。
*
* @param emitter 旧 SSE 连接
*/
private void sendKickedMessage(SseEmitter emitter) {
try {
emitter.send(SseEmitter.event()
.name("message")
.data(MessageConstants.KICKED));
} catch (Exception ignore) {
// 旧连接可能已断开,忽略通知失败
}
}
/** /**
* 断开指定用户的 SSE 连接 * 断开指定用户的 SSE 连接
* *
@@ -5,6 +5,7 @@ import cn.hutool.core.map.MapUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.utils.ThreadUtils; import org.dromara.common.core.utils.ThreadUtils;
import org.dromara.common.json.utils.JsonUtils; import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.push.constant.MessageConstants;
import org.dromara.common.push.dto.PushDTO; import org.dromara.common.push.dto.PushDTO;
import org.dromara.common.push.properties.MessageProperties; import org.dromara.common.push.properties.MessageProperties;
import org.dromara.common.redis.utils.RedisUtils; import org.dromara.common.redis.utils.RedisUtils;
@@ -61,6 +62,7 @@ public class WebSocketSessionManager implements PushSessionManager {
Map<String, WebSocketSession> sessions = USER_TOKEN_SESSIONS.computeIfAbsent(userId, key -> new ConcurrentHashMap<>()); Map<String, WebSocketSession> sessions = USER_TOKEN_SESSIONS.computeIfAbsent(userId, key -> new ConcurrentHashMap<>());
// 移除并关闭旧的同token会话,避免重复连接 // 移除并关闭旧的同token会话,避免重复连接
WebSocketSession oldSession = sessions.remove(token); WebSocketSession oldSession = sessions.remove(token);
sendKickedMessage(oldSession);
closeSession(oldSession, CloseStatus.NORMAL); closeSession(oldSession, CloseStatus.NORMAL);
// 存储新会话 // 存储新会话
sessions.put(token, session); sessions.put(token, session);
@@ -129,6 +131,18 @@ public class WebSocketSessionManager implements PushSessionManager {
toRemoveUsers.forEach(USER_TOKEN_SESSIONS::remove); toRemoveUsers.forEach(USER_TOKEN_SESSIONS::remove);
} }
/**
* 通知旧连接已被同 token 新连接替换。
*
* @param session 旧 WebSocket 会话
*/
private void sendKickedMessage(WebSocketSession session) {
if (session == null || !session.isOpen()) {
return;
}
sendMessage(session, MessageConstants.KICKED);
}
/** /**
* 订阅消息通道 * 订阅消息通道
* 注册消息消费者,监听Redis消息推送 * 注册消息消费者,监听Redis消息推送