客户端未接收到服务器发出的事件(使用socket.io和next.js)

g52tjvyc  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(127)

我正在尝试使用next.js和socket.io实现一个聊天应用程序。套接字io的客户端和服务器都在nextjs上(服务器使用API路由)。
我想创建一个聊天应用程序,允许用户创建“房间”,每个房间最多可以有2个连接的客户端(房间的创建者和另一个用户)。每个房间都有一个密码,用户在访问聊天框之前必须输入密码。我有一个页面pages/room/[id].tsx,这个页面验证密码,如果密码有效,然后显示聊天框。在这个页面本身,我初始化了一个socket.io客户端,并在验证了用户密码之后发出一个joinRoom事件。
(页数/房间/[id].tsx):

export default function ChatRoomID({
    id
}: {
    id: string
}) {
    const [socket, setSocket] = useState<Socket | null>(null);
    useEffect(() => {
        const socket = io();
        setSocket(socket);

        return () => {
            socket.disconnect();
        };
    }, []);

    function handleSubmit(password: string) {
        // ...verify password
        if (socket) {
            socket.emit(
                'joinRoom',
                id,
                (error: string | string, message: string) => {
                    if (error) {
                        toast({
                            title: 'Error',
                            description: error,
                        });
                    }
                }
            );
        }
    }

    return (
      <Chatbox id={id} socket={socket} />
    )
}

字符串
这是聊天框组件(该组件的props中的idsocket是从room/[id].tsx页面传递过来的,socket是在该页面初始化的):

export default function ChatBox({ socket }: { socket: Socket | null }) {

  useEffect(() => {
    if (!socket) return;

    console.log(socket.connected) // true
    
    socket.on('message', (data: { message: string; roomId: string }) => { // this event does not emit
      const { message, roomId } = data;
      console.log('Received message:', message); // does not log
      setMessages((prevMessages) => [...prevMessages, message]);
    });

    return () => {
      socket.off('message');
    };
  }, [socket]);

 // the function below is called when a user clicks the send message button
  const handleMessageSend = (e: FormEvent<HTMLFormElement>) => {
    e.preventDefault();

    if (socket) {
      const { message } = Object.fromEntries(new FormData(e.currentTarget));
      socket.emit('sendMessage', id, message); // this event emits properly
      e.currentTarget.reset();
      return;
    }
  };
}


最后,这是我的API路由器:

export default function handler(req: NextApiRequest, res: CustomApiResponse) {
  if (!res.socket.server.io) {
    const io = new Server(res.socket.server);
    res.socket.server.io = io;

    io.on('connection', (socket: Socket) => {
      console.log('io connection received');

      socket.on(
        'joinRoom',
        async (roomId: string, callback: Function) => {
          const roomDetails = await kv.get(roomId);

          if (!roomDetails) {
            return callback('Room not found', null);
          }

          const roomClients = io.sockets.adapter.rooms.get(roomId);
          if (roomClients && roomClients.size >= 2) {
            return callback('Room is full', null);
          }

          socket.join(roomId);
          callback(null, 'Successfully joined the room');
        }
      );

      socket.on('sendMessage', (roomId: string, message: string) => {
        console.log(`send message emitted`, roomId, message) // this is logged to console
        socket.to(roomId).emit('message', { message, roomId });
      });

    });
  }
  res.end();
}


这就是我想要实现的流程:密码验证->发出joinRoom事件(从客户端发出,服务器成功接收)->发出sendMessage事件(消息发送时,从ChatBox组件发出,服务器接收)->从sendMessage向聊天室发出message事件(客户端接收,客户端在聊天箱中显示接收到的消息)。
然而,问题是,message事件没有被发出。我已经检查了套接字是否仍然连接。下面是调试日志:

socket.io:socket emitting event ["sendMessage","3aa166ee-9c8c-419d-b213-6413bfef5e6f","a"] +1ms
  socket.io:socket dispatching an event ["sendMessage","3aa166ee-9c8c-419d-b213-6413bfef5e6f","a"] +1ms
Send message emitted 3aa166ee-9c8c-419d-b213-6413bfef5e6f a
  socket.io-parser encoding packet {"type":2,"data":["message",{"message":"a","roomId":"3aa166ee-9c8c-419d-b213-6413bfef5e6f"}],"nsp":"/"} +4ms
  socket.io-parser encoded {"type":2,"data":["message",{"message":"a","roomId":"3aa166ee-9c8c-419d-b213-6413bfef5e6f"}],"nsp":"/"} as 2["message",{"message":"a","roomId":"3aa166ee-9c8c-419d-b213-6413bfef5e6f"}] +1ms
  engine:transport readyState updated from closing to closed (polling) +30s
  engine:socket writing ping packet - expecting pong within 20000ms +659ms
  engine:socket sending packet "ping" (undefined) +0ms
  engine:socket flushing buffer to transport +1ms
  engine:ws writing "2" +662ms
  engine:ws received "3" +2ms
  engine:socket received packet pong +3ms
  engine:socket got pong +1ms


(logs所附的是sendMessage调度后的事件)
我似乎找不到问题,插座已连接,我已仔细检查房间ID和插座ID是否相同。请帮助。如果您也有改进此架构的建议,请与我们分享。
谢谢

zy1mlcev

zy1mlcev1#

我已经修复了它。这是因为我使用socket.to(roomId).emit(...),它向所有客户端发送事件,除了发送者,这就是为什么事件没有被发送。
ioServer)替换socket应该可以工作,因为io.in/io.to brodcast事件到所有连接的客户端,包括发送方。
查看https://socket.io/docs/v4/server-api/#serverinroom了解更多信息。

相关问题