发送几条消息后,WebSocket readyState 停留在 0

Posted

技术标签:

【中文标题】发送几条消息后,WebSocket readyState 停留在 0【英文标题】:WebSocket readyState stuck at 0 after a couple of messages are sent 【发布时间】:2021-05-18 00:17:03 【问题描述】:

我正在尝试使用 Web 套接字开发一个实时聊天应用程序并做出反应,但是在我尝试提交几条消息(大约 30 条)后,Web 套接字卡在了 CONNECTING 状态。我已经设置好了,所以当它发送消息时,它禁用了发送按钮,以防止用户发送垃圾邮件太快,但不幸的是我仍然遇到同样的问题。

// id is a uuid() string
const ws = new WebSocket(`ws://localhost:3001/chat/$id`);

useEffect(() => 
        ws.onmessage = function(evt)
            try
                const user_id = parseInt(evt.data.split("")[0]);
                const message = evt.data.slice(1);
                const currentTime = new Date();
                const currentUTC = currentTime.toUTCString();
                const timestamp = new Date(currentUTC);
                setMessages(messages => [...messages, user_id, message, timestamp])
             catch(e)
                console.log(e);
            
        

        ws.onclose = function(evt)
            console.log("DISCONNECTED!!")
            ws.close();
        

        ws.onerror = function(evt)
            console.log(evt);
            ws.close();
        
    , []);


useEffect(() => 
        async function postMessageToAPI() 
            
            const messsageToSend = 
                unique_id: id,
                message: formData.message, 
                user_id: user.id, 
                group_chat_id: room.id
            
            // Convert to unviersal time UTC and send it to database
            let currentUTC = new Date();
            currentUTC.toUTCString();
            messsageToSend.timestamp = currentUTC;

            await AnonChatApi.sendChatMessage(messsageToSend);
        

        if(sendMessage)
            ws.onopen = function()
                // add user_id to the start of the message string
                const message = `$user.id` + formData.message;
                ws.send(message);
            
            postMessageToAPI();
            resetFormData();
            setTimeout(() => 
                setSendMessage(false)
            , 1000);
        
    , [sendMessage]);

const goBackHome = () => 
        ws.close();
        history.push('/');
    

【问题讨论】:

你没有显示打开或关闭套接字的代码,你能补充一下吗? 如果您在每条消息后都关闭套接字,那么您可能不应该使用 websocket。我无法从您的代码中判断是否是这种情况,但您的描述似乎暗示了这一点。 @Codebling,我添加了打开和关闭 websocket 的代码。我不是在每条消息后都尝试关闭 websocket,我只是通过一次发送多条消息来测试错误,它最终卡在 readyState 0 上。感谢您查看我的代码! 【参考方案1】:

我可以看到您正在使用 Hooks,因此您还必须使用功能组件。 我认为初始化 websocket 的代码是否正确

const ws = new WebSocket(`ws://localhost:3001/chat/$id`);

在函数的顶部?

提醒一下,每当你的组件被渲染时,定义你的函数组件的函数就会运行。任何未保存在状态中的东西都会丢失。这包括你的 websocket - 每次渲染都会创建一个新的 websocket,你的异步函数可能会在旧的 websocket 上发送数据(来自以前的渲染),React 可能会在控制台中警告你有内存泄漏。

useEffect 是这里的正确做法,但是 websocket 也需要保存在 state 中。

YourFunctionComponent() 
  const [ws, setWs] = useState(null);

  useEffect(() => 
    if (ws == null) 
      setWs(new WebSocket(`ws://localhost:3001/chat/$id`));
    
    return () => 
      // A function returned from useEffect will
      // get called on component unmount. 
      // Use this function to clean up your connection and 
      // close your websocket!

      // clean up, e.g.
      // ws.send('closing due to unmount!');
      
      ws.close();
      setWs(null);
    
  , [ws, setWs]);


  // Add `ws` as a dependency in the useEffect()s you posted above
  useEffect(() => 
    ws.onmessage = function(evt)
[--snip--]
    
  , [ws]);

  useEffect(() => 
    async function postMessageToAPI() 
[--snip--]
    
  , [sendMessage, ws]);

【讨论】:

解决了这个问题,谢谢!我还需要添加检查以等待设置 ws 否则我会收到诸如“无法读取 null 的消息”之类的错误。 @Allen 真棒!

以上是关于发送几条消息后,WebSocket readyState 停留在 0的主要内容,如果未能解决你的问题,请参考以下文章

在其他几条消息完成后发送消息而不使用外部存储?

Django 频道 + 在发布请求后发送 websocket 消息

WebSocket发送消息后自动断开的问题

WebSocket发送消息后自动断开的问题

java websocket上线后如何发送离线用户的消息?

Websocket4Net 发送多条消息