【问题标题】:Check if a WebSocket server is available without erroring检查 WebSocket 服务器是否可用且不出错
【发布时间】:2021-03-04 04:59:53
【问题描述】:

我的网络应用需要定期检查服务器是否已启动。这允许用户以任一顺序启动服务器和客户端。

为此,我只需从 setTimeout 处理程序内部调用 WebSocket 构造函数。

从使用的角度来看,这种策略效果很好,但是对于开发人员来说,这让我很烦,因为我在 Chrome 中看到了很多控制台错误:

remote.html:194 WebSocket connection to 'ws://localhost:8082/' failed: Connection closed before receiving a handshake response
remote.html:194 WebSocket connection to 'ws://localhost:8082/' failed: Connection closed before receiving a handshake response
remote.html:194 WebSocket connection to 'ws://localhost:8082/' failed: Connection closed before receiving a handshake response

这些并不是真正的错误,因为我的 Web 应用程序在服务器不可用的情况下完全正常。它重复调用WebSocket 构造函数(MDN)只是为了检查服务器是否已经启动。

有没有更好的方法来做到这一点?就上下文而言,我的 Web 应用程序是在设备上运行的原生 C++ 应用程序的“远程控制”。

【问题讨论】:

  • 那么,从 Chrome 的控制台部分或终端和日志中过滤消息的唯一问题是什么?

标签: javascript browser websocket


【解决方案1】:

使用SharedWorker! 时会抑制错误!请尝试以下操作:

ma​​in.html

<!doctype html>
<html>
  <head>
    <title>WS Test</title>
    <script type="text/javascript"> (async () => {
      
      await new Promise(r => window.addEventListener('load', r));
            
      let worker = new SharedWorker('worker.js');
      worker.port.onmessage = evt => console.log('MSG:', evt.data);
      
    })() </script>
  </head>
  <body></body>
</html>

worker.js

let ports = [];
onconnect = ({ ports: [ port ] }) => ports.push(port);

(async () => {
  
  while (true) {
    
    await new Promise(r => setTimeout(r, 1000));
    
    let ws = new WebSocket('ws://localhost:9999/');
    ws.addEventListener('error', evt => ports.forEach(port => port.postMessage('error')));
    ws.addEventListener('open', evt => ports.forEach(port => port.postMessage('open')));
    
  }
  
})();

这给了我反馈,WebSocket 正在达到Error,但不会在日志中产生任何额外的噪音:

(请注意,“一些消息已移至问题面板”是由于仓促的不符合标准的测试 html - 如果您将此解决方案转移到您自己的代码中,它将消失!)

SharedWorker 没有指向任何特定选项卡的必要链接 - 因此,我看不出为什么 SharedWorker 的错误可能会在 any 的选项卡控制台中显示为噪音环境。

【讨论】:

  • 我喜欢这个解决方案!它减轻了轮询循环的负担,这似乎是一个不错的副作用。
  • 是的..这个家伙有答案
【解决方案2】:

请注意,连接错误消息主要由浏览器本身处理,而不是 JS 运行时。

如果您想显式抑制运行时错误,可以使用onerror 事件处理程序。 示例:

window.onerror = function(message, url, lineNumber) {
        // you can also filter out certain messages in this handler
        return true; // prevents all error messages from displaying
};

另外,考虑使用设置健康检查 HTTP 端点之类的东西,而不是打开 WS 连接。

正如您的错误消息所述,您在打开后立即关闭连接,您不应该这样做,而是可以保持一个 WS 连接打开并使用 ping/pong WebSocket 消息检查连接是否处于活动状态,从而确保服务器处于还活着。如果连接关闭,可以定期重试连接 setInterval,如果连接尝试成功,使用clearInterval重用之前的WS对象变量和销毁区间。

【讨论】:

  • 谢谢!是的,我可能需要使用onerror 处理程序来解决这个问题,但我希望有更好的解决方案。我没有在任何地方打电话给close(),尽管错误消息说了什么。我相信这是隐式完成的,因为 HTML 标准说:```如果建立 WebSocket 连接算法失败,则会触发 WebSocket 连接算法失败,然后调用关闭 WebSocket 连接算法```我认为你的健康检查的想法不适用于我的情况,因为服务器嵌入在设备上运行的本机 C++ 应用程序中。
  • 刚才做了一个实验:在Chrome 88(macOS)中,WebSocket连接失败时不会触发window.onerror。不过这是个好主意。
  • @prideout 但您正尝试与嵌入在设备上运行的本机 C++ 应用程序中的服务器建立 WS 连接,对吗?为了建立 WS 连接,客户端发送带有正确标头的 HTTP GET 请求和带有 HTTP 101 状态码(切换协议,如果我没记错的话)的服务器响应,这个阶段也称为握手。为什么只使用一个 HTTP 请求而不是执行握手和协议升级会出现问题?
  • @prideout 无论如何,您也可以使用console.clear 功能删除控制台记录,如果这适合您
  • 您对我的问题上下文的理解是正确的。是的,我可以使用 HTTP GET 轮询服务器,但是我遇到了同样的问题,即在 Chrome 控制台中看到恼人的错误消息。感谢您的帮助,这些都是好主意。我觉得这是对标准的疏忽——我想做的并不疯狂。
【解决方案3】:

所有错误都被抑制,但这不能是下面的原因

WebSocket connection to 'ws://localhost:5000/tech-support' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED

无法捕获该错误消息,该错误消息与创建 WebSocket 对象的代码异步发生。

更多详情:Javascript doesn't catch error in WebSocket instantiation

【讨论】:

    【解决方案4】:

    Websockets 只是升级的 HTTP/HTTPS 端点,所以你可以做一个请求并检查你是否可以升级

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-05-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-03
      • 1970-01-01
      相关资源
      最近更新 更多