You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.17 14:36:05