websocket本身不提供按http session id路由消息的能力,因其与http session完全独立;正确做法是在连接建立时用userid等业务标识显式注册到concurrenthashmap中,并据此精准推送。

WebSocket 本身不提供“按 Session ID 发消息”的能力,Session 是 HTTP 概念,而 WebSocket 连接一旦建立就脱离了 HTTP 生命周期;服务端真正能用的只有连接对应的 Session 对象(如 Java 的 javax.websocket.Session)或自定义的连接标识(如 userId)。直接拿 HTTP Session ID 去路由 WebSocket 消息,99% 会失败。
为什么不能用 HttpSession ID 当 WebSocket 路由键
HTTP Session 和 WebSocket Session 完全独立:前者靠 Cookie 维持、有超时机制、可能被集群 session 复制干扰;后者是长连接句柄,生命周期从 @OnOpen 到 @OnClose。两者 ID 格式、生成逻辑、存活时间均无关联。
- 常见错误:前端传
jsessionid到后端,服务端用它查HttpSession,再试图 getAttribute("websocketSession") —— 这个属性根本不会自动存在 - Spring Boot + Tomcat 环境下,即使你手动把
Session存进HttpSession,重启或集群也会丢失 - Netty/Undertow 等非 Servlet 容器压根没有
HttpSession,这条路直接不通
正确做法:用 userId 或 connectionId 显式注册连接
服务端必须在连接建立时,主动绑定一个**业务可识别、稳定、唯一**的标识到该 WebSocket 连接上。这个标识不能是随机 UUID(前端无法告知目标是谁),也不能是临时 token(难校验),最合适的是登录态中的 userId。
- Java 示例中,
@ServerEndpoint("/chat/{userId}")是最干净的方式:URL 路径自带标识,@PathParam("userId")可直接提取 - 如果必须走 query 参数(如鉴权需要 token),确保服务端在
@OnOpen阶段解析并校验,成功后存入ConcurrentHashMap<string session></string>,key 为userId - 避免用 IP+Port 当 key:NAT、代理、移动端切换网络会导致重复或错绑
- 注册前务必检查
userId是否已在线 —— 防止多端登录时旧连接被覆盖
发送消息时如何精准命中目标 Session
拿到目标 userId 后,不是去“查 Session ID”,而是从你维护的映射表里取对应 Session 实例,然后调用 session.getAsyncRemote().sendText()。
- 别用
session.isOpen()做前置判断 —— 它可能返回true但实际已断连,应配合心跳或捕获IOException - 发送失败时,
sendText()的 CompletableFuture 会 completeExceptionally,必须whenComplete((r, e) -> { if (e != null) removeSession(userId); }) - 不要在 send 前加 synchronized ——
ConcurrentHashMap已线程安全,锁粒度太大反而卡住整个连接池 - 如果目标
userId不在 map 中,说明对方不在线,此时应存离线消息,而不是抛异常或静默丢弃
前端发消息时必须带 toUserId 字段
服务端靠这个字段查目标连接。如果你只传纯文本(如 socket.send("hi")),服务端根本不知道该推给谁 —— 所有私聊逻辑都会崩。
- 消息体必须是 JSON 对象,至少含
toUserId、content、fromUserId(后者用于防伪造) - 示例:
{"type":"private","toUserId":"789","fromUserId":"123","content":"测试"} - 前端发送前要校验
toUserId是否为空或非法字符(如"../"),否则可能触发服务端路径遍历类 bug - 服务端收到后必须先
JSON.parse()再取字段,不能直接data.split(",")—— 字符串内容含逗号就会解析错
最容易被忽略的一点:连接注册和注销必须成对、原子。有人只在 @OnOpen 存 map,却忘了在 @OnClose 或 @OnError 里删 —— 一星期后内存暴涨,ConcurrentHashMap 里全是僵尸连接。











