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

Next.js结合Socket.io开发实时聊天的在线用户列表功能实现问题咨询

实现方案

核心逻辑

  • 借助Next.js API路由底层HTTP服务全局挂载的特性,将在线用户列表和Socket.io实例绑定到同一个全局对象上,避免状态丢失
  • 客户端连接成功后主动上报自定义昵称,服务端维护socket.id与用户昵称的映射关系
  • 用户加入/离开时,服务端主动向聊天房间广播最新的在线用户列表

服务端代码修改

你原有代码存在一个明显错误:disconnect事件需要监听在单个socket实例上,而非IO实例,否则无法触发。完整修改后代码如下:

import { NextApiRequest } from 'next';
import { NextApiResponseServerIO } from '../../types/next';
import { Server as ServerIO } from 'socket.io';
import { Server as NetServer } from 'http';

export const config = {
    api: {
        bodyParser: false
    }
}

export default async (req: NextApiRequest, res: NextApiResponseServerIO) => {
    if (!res.socket.server.io) {
        console.log("** New Socket.io server **")
        // 适配Next底层服务为http服务
        const httpServer: NetServer = res.socket.server as any;
        const io = new ServerIO(httpServer, {
            path: '/api/socketio'
        });
        // 初始化全局在线用户列表,key为socket.id,value为用户昵称
        res.socket.server.users = new Map();

        io.on('connect', (socket) => {
           socket.join('main');
           const users = res.socket.server.users;
           const ioInstance = res.socket.server.io;

           // 监听客户端上报的昵称
           socket.on('setNickname', (nickname: string) => {
               // 存储用户信息
               users.set(socket.id, nickname);
               // 向全房间广播最新用户列表
               ioInstance.to('main').emit('updateUsersList', 
                   Array.from(users.entries()).map(([id, name]) => ({ id, nickname: name }))
               );
           });

           // 监听用户断开连接
           socket.on('disconnect', () => {
               // 删除离开的用户
               users.delete(socket.id);
               // 广播最新列表
               ioInstance.to('main').emit('updateUsersList', 
                   Array.from(users.entries()).map(([id, name]) => ({ id, nickname: name }))
               );
           });
        });

        res.socket.server.io = io;
    }
    res.end();
}

客户端代码修改

连接成功后上报用户昵称,接收广播后更新本地用户列表即可:

useEffect((): any => {
    const url = process.env.NEXT_BASE_URL as string | "";
    // 连接socket服务端
    const socket = io(url, {
      path: "/api/socketio",
    });

    // 打印socket连接状态
    socket.on("connect", () => {
      dispatch(connect(socket.id));
      dispatch(updateId(socket.id));
      // 替换为你实际存储的用户自定义昵称变量
      const userNickname = "当前用户的昵称";
      socket.emit('setNickname', userNickname);
    });
    
    // 收到消息时更新聊天记录
    socket.on("message", (message: IMsg) => {
      dispatch(receive(message));
    });

    socket.on('updateUsersList', (users: Array<{id: string, nickname: string}>) => {
      // 新增:更新全局状态中的在线用户列表
      dispatch(setOnlineUsers(users));
      console.log("最新在线用户", users)
    })

    // 组件卸载时断开服务端连接
    return () => {
      socket.disconnect();
      dispatch(disconnect(socket));
    };
  }, []);

内容的提问来源于stack exchange,提问作者Jason Long

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 06:36:04