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

时间:2018-03-21 13:46:16

标签: javascript node.js websocket

我发现Chrome和Firefox中的WebSockets在一分钟不活动后断开连接。基于我在网上看过的东西,我都会责怪代理或某些服务器设置或其他东西,但这不会发生在IE或Edge中。似乎服务器在一分钟不活动之后断开连接,这将适用于IE和Edge,就像Chrome和Firefox一样。

有谁知道这是为什么?是否记录在任何地方?我知道一种可能的方法来通过ping来阻止它,但我更感兴趣的是它为什么会发生。断开连接时给出的原因代码是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);
});

4 个答案:

答案 0 :(得分:4)

正如我从研究中所理解的那样,这是由于在没有数据发送的一段时间内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

答案 1 :(得分:4)

WebSocket协议规范定义了Ping和Pong帧,可用于保持活动,心跳,网络状态探测。 Ping 表示客户端/服务器正在发送iq以告知对方服务器/客户端保持连接活动,另一方将发送具有相同功能的 pong 的确认有效载荷数据。

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

了解详情:http://vunse.blogspot.in/2014/04/websocket-ping-pong.html

答案 2 :(得分:3)

  

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

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

JavaScript API未公开的

The WebSocket protocol includes support for a protocol level ping。它比通常实现的用户级别ping更低级。

ping - pong流量会重置任何网络中介(代理,负载均衡器等)中的计时器 - 并且它们都会连接以标记过时的连接以进行关闭(例如,{ {3}})。

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

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

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

关于nginx默认超时的一些细节(当代理WebSocket连接时),你可以阅读@Hendry的答案。

答案 3 :(得分:0)

也许不是一个干净的解决方案,但这是我在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()