websocket需应用层实现主题订阅,客户端发送json格式订阅/退订指令,服务端用内存map/set维护主题-连接映射并精准广播,集群下需redis等同步状态。

WebSocket 本身不内置“主题订阅”机制,动态订阅主题频道需要靠应用层协议设计来实现——本质是客户端发送结构化消息告诉服务端“我要加入哪个主题”,服务端据此维护连接与主题的映射关系,并转发对应消息。
定义统一的订阅消息格式
服务端需能识别订阅/取消订阅指令。推荐使用 JSON 消息体,包含操作类型、主题名等字段:
-
订阅:
{"type":"subscribe","topic":"news/sports"} -
退订:
{"type":"unsubscribe","topic":"news/sports"} -
批量订阅(可选):
{"type":"subscribe","topics":["chat/general","alerts/urgent"]}
避免用自定义字符串拼接(如 SUB:news/sports),JSON 更易扩展、调试和兼容多语言后端。
服务端维护主题-连接映射关系
以 Node.js + ws 库为例,用 Map 或 Set 管理主题与客户端连接的关联:
- 每个主题对应一个
Set<websocket></websocket>,插入/删除连接即可完成订阅/退订 - 收到订阅请求时,校验 topic 格式(如是否含非法字符)、权限(如用户是否有权访问
admin/*) - 退订时从对应 Set 中移除该连接;连接关闭时,遍历所有主题 Set 清理该连接
注意:不要把整个 WebSocket 实例存进数据库或跨进程共享,只在内存中维护映射,适合单实例部署;集群场景需配合 Redis Pub/Sub 或消息队列同步订阅状态。
客户端动态调用 subscribe/unsubscribe 方法
封装 WebSocket 实例,提供语义化 API,避免每次手动 send 原始 JSON:
class TopicSocket {
constructor(url) {
this.ws = new WebSocket(url);
this.ws.onmessage = (e) => this._handleMessage(JSON.parse(e.data));
}
subscribe(topic) {
this.ws.send(JSON.stringify({ type: 'subscribe', topic }));
}
unsubscribe(topic) {
this.ws.send(JSON.stringify({ type: 'unsubscribe', topic }));
}
_handleMessage(data) {
if (data.type === 'message' && data.topic) {
// 触发对应主题的事件,例如:this.emit(`topic:${data.topic}`, data.payload)
}
}
}
实际使用时可按需扩展:支持 Promise 化订阅结果、自动重连后恢复订阅、防重复订阅等。
服务端广播时按主题精准投递
发布消息时,不再群发所有连接,而是只推送给订阅了该主题的客户端:
- 接收外部事件(如数据库变更、HTTP 接口触发)后,解析目标 topic(如
orders/123) - 查出
topicMap.get('orders/123')对应的 WebSocket 集合 - 遍历发送消息:
client.readyState === WebSocket.OPEN && client.send(JSON.stringify({...}))
可进一步支持通配符(如 orders/*),但需在订阅时做模式匹配预处理,或改用更成熟的发布订阅中间件(如 Redis Pub/Sub + 主题路由)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











