Chrome 和 Firefox 中的 WebSockets 在闲置一分钟后断开连接

新手上路,请多包涵

我发现 Chrome 和 Firefox 中的 WebSockets 在闲置一分钟后就会断开连接。根据我在网上看到的东西,我都将责任归咎于代理或某些服务器设置或其他东西,但这不会发生在 IE 或 Edge 中。似乎如果套接字在一分钟不活动后被服务器断开连接,这将适用于 IE 和 Edge,就像 Chrome 和 Firefox 一样。

有人知道为什么吗?它记录在任何地方吗?我知道一种通过 ping 来阻止它的可能方法,但我对它发生的原因更感兴趣。 disconnect给出的原因码是1006,表示浏览器关闭了连接。不会抛出任何错误,也不会触发套接字的 onerror 事件。

该项目建立在 https://glitch.com/edit/#!/noiseless-helmet 上,您可以在其中查看和运行所有内容。客户端页面在此处提供: https ://noiseless-helmet.glitch.me/

这是我的客户页面:

 <div id="div">
</div>
<script>
  let socket = new WebSocket("wss://noiseless-helmet.glitch.me/");
  socket.onmessage = function(event) {
    div.innerHTML += "<br>message " + new Date().toLocaleString() + " " + event.data;
  };
  socket.onopen = function (event) {
    div.innerHTML += "<br>opened " + new Date().toLocaleString();
    socket.send("Hey socket! " + new Date().toLocaleString());
  };
  socket.onclose = function(event) {
    div.innerHTML += "<br>socket closed " + new Date().toLocaleString();
    div.innerHTML += "<br>code: " + event.code;
    div.innerHTML += "<br>reason: " + event.reason;
    div.innerHTML += "<br>clean: " + event.wasClean;
  };
  socket.onerror = function(event) {
    div.innerHTML += "<br>error: " + event.error;
  };
</script>

这是我的 Node.js 服务器代码:

 var express = require('express');
var app = express();
app.use(express.static('public'));

let server = require('http').createServer(),
  WebSocketServer = require('ws').Server,
  wss = new WebSocketServer({ server: server });

app.get("/", function (request, response) {
  response.sendFile(__dirname + '/views/index.html');
});

let webSockets = [];
wss.on('connection', function connection(socket) {
  webSockets.push(socket);
  webSockets.forEach((w) => { w.send("A new socket connected"); });
  socket.on('close', (code, reason) => {
    console.log('closing socket');
    console.log(code);
    console.log(reason);
    let i = webSockets.indexOf(socket);
    webSockets.splice(i, 1);
  });
});

server.on('request', app);
server.listen(process.env.PORT, function () {
  console.log('Your app is listening on port ' + server.address().port);
});

原文由 user12861 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 2.2k
2 个回答

似乎如果套接字在一分钟不活动后被服务器断开连接,这将适用于 IE 和 Edge,就像 Chrome 和 Firefox 一样。

嗯,不,它没有。 IE 和 Edge 可能 正在实施一个 ping 数据包作为 WebSocket 协议的一部分。

WebSocket 协议包括对 JavaScript API 不公开的协议级别 ping 的支持。它比经常实施的用户级别 ping 级别低一些。

这个 ping - pong 流量会重置任何网络中介(代理、负载平衡器等)中的计时器 - 它们所有时间连接都标记为关闭的陈旧连接(例如, Heroku 设置连接时间为 55 秒)。

大多数浏览器信任服务器来实现 ping ,这是礼貌的(因为服务器需要管理它们的负载和它们的 ping 超时……

…然而,这也有点令人沮丧,因为浏览器不知道连接是否异常丢失,并且 JavaScript 不会为 WebSocket 协议发出事件 ping 。这就是为什么许多 JavaScript 客户端实现用户级 ping(即 JSON {event: "ping", data: {...}} 或另一个“空”事件消息)的原因。

不管怎样,我只是想指出你的假设是不正确的,这仍然是超时发生,浏览器行为的差异可能与浏览器本身有关。

有关 nginx 默认超时(代理 WebSocket 连接时)的一些细节,您可以阅读@Hendry 的回答。

原文由 Myst 发布,翻译遵循 CC BY-SA 4.0 许可协议

据我从研究中了解到,这是由于 websocket 在一段时间内没有发送数据时超时造成的。这可能是每个浏览器。

您可以使用 ping 来解决此问题,或者在需要再次使用套接字时重新连接。

当服务器端和浏览器端不使用套接字时,不保持套接字打开是有意义的。例如,Chrome 有一个可以打开多少个连接的限制,如果限制是 64 个连接并且你打开了 64 个选项卡(这对我来说很可能因为我总是打开大量的选项卡)并且每个选项卡都连接到一个服务器,无法完成更多连接(实际上类似的事情发生在我身上一次,当我用完 Chrome 中的可用套接字时,很有趣)。

proxy_read_timeout ( http://nginx.org/r/proxy_read_timeout ) 也适用于 WebSocket 连接。如果你的后端长时间不发送任何东西,你必须撞上它。或者,您可以将后端配置为定期发送 websocket ping 帧以重置超时(并检查连接是否仍然存在)。

https://forum.nginx.org/read.php?2,236382,236383#msg-236383

Web 套接字有 60 秒的空闲超时:如果您不通过 ping 和 pong 帧使用心跳或类似信号,则套接字假定用户已关闭页面并关闭套接字以节省资源。

https://www.codeproject.com/Questions/1205863/Websocket-is-closed-after-min

https://github.com/tornadoweb/tornado/issues/1070

原文由 Hendry 发布,翻译遵循 CC BY-SA 3.0 许可协议

推荐问题