javascript Chrome 和 Firefox 中的 WebSockets 在不活动一分钟后断开连接

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/49408031/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 08:34:16  来源:igfitidea点击:

WebSockets in Chrome and Firefox Disconnecting After One Minute of Inactivity

javascriptnode.jswebsocket

提问by user12861

I have found that WebSockets in Chrome and Firefox disconnect after exactly one minute of inactivity. Based on stuff I've seen online, I was all set to blame proxies or some server settings or something, but this does not happen in IE or Edge. It seems like if sockets are disconnected by the server after one minute of inactivity that would apply to IE and Edge just as much as Chrome and Firefox.

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

Does anyone know why this is? Is it documented anywhere? I know a possible way to stop it by pinging, but I'm more interested in why it's happening. The reason code given on disconnect is 1006, indicating that the browser closed the connection. No errors are thrown and the onerror event for the socket is not triggered.

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

This project was built at https://glitch.com/edit/#!/noiseless-helmetwhere you can see and run everything. The client page is served here: https://noiseless-helmet.glitch.me/

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

Here is my client page:

这是我的客户页面:

<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>

And here is my Node.js server code:

这是我的 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);
});

采纳答案by Myst

It seems like if sockets are disconnected by the server after one minute of inactivity that would apply to IE and Edge just as much as Chrome and Firefox.

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

Hmmm, no, it doesn't. IE and Edge mightbe implementing a pingpacket as part of the WebSocket protocol.

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

The WebSocket protocol includes support for a protocol level pingthat the JavaScript API doesn't expose. It's a bit lower-level than the user level pinging that is often implemented.

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

This ping-pongtraffic resets the timers in any network intermediaries (proxies, load balancers, etc') - and they all time connections to mark stale connections for closure (for example, the Heroku setup times connections at 55 seconds).

ping-pong流量会重置任何网络中介(代理、负载平衡器等)中的计时器 - 它们都会对连接进行计时以将过时的连接标记为关闭(例如,Heroku 设置将连接时间设置为 55 秒)。

Most browsers trust the server to implement the ping, which is polite (since servers need to manage their load and their timeout for pinging...

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

...however it's also slightly frustrating, since browsers have no idea if a connection was abnormally lost. This is why many JavaScript clients implement a user level ping (i.e., a JSON {event: "ping", data: {...}}or another "empty" event message).

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

Anyway, I just wanted to point out that your assumption was incorrect, this is still a timeout occurring and the difference in browser behavior is probably related to the browsers themselves.

无论如何,我只是想指出您的假设是不正确的,这仍然是超时发生并且浏览器行为的差异可能与浏览器本身有关。

For a few specifics regarding nginx default timeouts (when proxying WebSocket connections) you can read @Hendry's answer.

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

回答by Hendry

As much as i understood from researching this, this is caused by websocket timing out over a period of time when no data is sent. This is probably per browser.

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

You could use pings to resolve this or just reconnect when you need to use the socket again.

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

It makes sense to not keep sockets open when they are not used from server side as from browser side. For example, Chrome has a limit how many connections can be open, if the limit would be 64 connections and you have open 64 tabs (which is very likely for me as i always have loads of tabs open) and each tab is connected to a server, no more connections could be done (Actually similar thing happened to me once, when i ran out of available sockets in Chrome, funny).

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

There is proxy_read_timeout (http://nginx.org/r/proxy_read_timeout) which as well applies to WebSocket connections. You have to bump it if your backend do not send anything for a long time. Alternatively, you may configure your backend to send websocket ping frames periodically to reset the timeout (and check if the connection is still alive).

有 proxy_read_timeout ( http://nginx.org/r/proxy_read_timeout) 也适用于 WebSocket 连接。如果您的后端长时间不发送任何内容,您必须对其进行碰撞。或者,您可以将后端配置为定期发送 websocket ping 帧以重置超时(并检查连接是否仍然有效)。

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

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

Web Sockets have an idle timeout of 60 seconds: if you do not use a heartbeat or similar via ping and pong frames then the socket assumes that the user has closed the page and closes the socket to save resources.

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

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

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

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

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

回答by Sakshi Nagpal

The WebSocket protocol specification defines Ping and Pong frames that can be used for keep-alive, heart-beats, network status probing. Pingmeans client/server is sending an iq to tell the other side server/client that to keep the connection alive and also the other side will send an acknowledgement with ponghaving same payload data.

WebSocket 协议规范定义了 Ping 和 Pong 帧,可用于保持活动、心跳、网络状态探测。Ping意味着客户端/服务器正在发送一个 iq 来告诉另一端服务器/客户端保持连接处于活动状态,并且另一端将发送具有相同有效载荷数据的pong的确认。

You can also define a timeout when the browser stops respond or be considered dead.

您还可以定义浏览器停止响应或被视为死机时的超时。

read more: http://vunse.blogspot.in/2014/04/websocket-ping-pong.html

阅读更多:http: //vunse.blogspot.in/2014/04/websocket-ping-pong.html

回答by Json

Maybe not a clean solution but this is how I implemented websocket in JS to automatically reconnect when disconnected

也许不是一个干净的解决方案,但这就是我在 JS 中实现 websocket 以在断开连接时自动重新连接的方式

var socket_main
const mainSocketMessageListener = (event) => {
  //retreive the data here
  console.log(event.data)
}

const mainSocketOpenListener = (event) => {
  console.log("Websocket opened")
  //Example of sending message to websocket here
  socket_main.send(JSON.stringify({
    event: "subscribe",
    data: ["all"]
  }))
}

const mainSocketCloseListener = (event) => {
  if (socket_main) {
    console.error('Websocket disconnected.')
  }
  socket_main = new WebSocket('wss://ws.example.com')
  socket_main.addEventListener('open', mainSocketOpenListener)
  socket_main.addEventListener('message', mainSocketMessageListener)
  socket_main.addEventListener('close', mainSocketCloseListener)
}

//connect the first time
mainSocketCloseListener()