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
相关产品推荐
相关产品推荐

