fix 修复 push 模块 sse/ws 浏览器多标签页互挤掉线问题
This commit is contained in:
+5
@@ -31,4 +31,9 @@ public interface MessageConstants {
|
|||||||
* 心跳响应标识
|
* 心跳响应标识
|
||||||
*/
|
*/
|
||||||
String PONG = "pong";
|
String PONG = "pong";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同一 token 的新连接替换旧连接时发送给旧连接的控制消息。
|
||||||
|
*/
|
||||||
|
String KICKED = "kicked";
|
||||||
}
|
}
|
||||||
|
|||||||
+16
@@ -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 连接
|
||||||
*
|
*
|
||||||
|
|||||||
+14
@@ -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消息推送
|
||||||
|
|||||||
Reference in New Issue
Block a user