如何使用NestJS向单个WebSocket客户端定向推送消息
NestJS Websocket 定向发送消息解决方案
可以实现向单个指定客户端发送消息,有两种常用实现方案:
方案一:基于用户ID与SocketID映射
- 实现思路:维护一个映射表存储用户业务ID(即你代码里的
profileId)和对应socket连接id的对应关系,发送消息时通过接收方profileId拿到对应的socketId,定向推送 - 适用场景:单实例部署的服务
修改后的完整代码如下:
export class ChatGateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect { constructor(private conversationService: ConversationService) {} @WebSocketServer() server: Server; // 单实例场景用内存Map存储,分布式场景可替换为Redis等共享存储 private userSocketMap = new Map<ID, string>() // 客户端连接时绑定用户id和socketId handleConnection(client: Socket) { // 客户端连接时一般会在query或者auth字段携带当前登录用户的profileId,按需调整取值逻辑 const currentProfileId = client.handshake.query.profileId as ID if (currentProfileId) { this.userSocketMap.set(currentProfileId, client.id) } } // 客户端断开连接时删除映射 handleDisconnect(client: Socket) { const currentProfileId = client.handshake.query.profileId as ID if (currentProfileId) { this.userSocketMap.delete(currentProfileId) } } @SubscribeMessage('sendMessage') async handleMessage( client: Socket, payload: { senderProfileId: ID; recieverProfileId: ID; conversationId: ID; message: string; createdAt: Date; }, ) { await this.conversationService.createMessage({ message: payload.message, createdAt: payload.createdAt, senderProfileId: payload.senderProfileId as string, conversationId: payload.conversationId as string, }); // 定向推送消息给指定用户 const receiverSocketId = this.userSocketMap.get(payload.recieverProfileId) if (receiverSocketId) { this.server.to(receiverSocketId).emit('receiveMessage', payload); } else { // 接收方不在线时,可自行实现离线消息存储逻辑 } } }
方案二:基于Socket.IO专属房间实现(更推荐)
- 实现思路:利用Socket.IO的房间机制,每个用户连接时主动加入一个以自己
profileId为名称的专属房间,发送消息时直接向该房间推送即可,无需自行维护映射关系,天然支持分布式部署(搭配socket.io适配器即可) - 适用场景:单实例/多实例分布式部署场景
核心修改代码如下:
// 连接时加入专属房间 handleConnection(client: Socket) { const currentProfileId = client.handshake.query.profileId as ID if (currentProfileId) { client.join(currentProfileId) } } // 发送消息时直接向接收方的专属房间推送,不需要维护映射表 this.server.to(payload.recieverProfileId).emit('receiveMessage', payload);
注意事项
- 你原有代码里事件名
recieveMessage拼写有误,正确拼写为receiveMessage,需前后端统一避免接收不到 - 如果是多实例部署的场景,方案一需要用Redis等共享存储替换内存Map,方案二需要搭配
socket.io-redis等适配器实现跨实例的房间消息同步
内容的提问来源于stack exchange,提问作者abbasali1997
相关产品推荐
相关产品推荐

