Sockjs/SocketIO在Apache代理后断开连接的延迟

4

我需要处理用户从我的sockjs应用程序运行在xhr-polling模式下断开连接的情况。当我连接到本地主机时,一切都按预期工作。当我在nodejs和浏览器之间放置apache时,关闭浏览器和断开事件在nodejs内部之间存在约20秒的延迟。我的apache代理配置如下:

<Location />
  ProxyPass http://127.0.0.1:8080/
  ProxyPassReverse http://127.0.0.1:8080/
</Location>

文件的其余部分都是默认设置,您可以在此处查看。我尝试过使用ttl = 2和timeout = 2选项进行操作,但要么没有任何更改,要么每2秒重新连接一次而不关闭浏览器。如何减少Apache引入的额外断开超时,在其默认设置中的某个地方?

1
SockJS 首先尝试使用 WebSockets,如果不可用,则使用轮询。当您在其中加入 Apache 时,只传递 HTTP,因此不允许 WS 协议,因此强制使用轮询。如果您在 Apache 文件中启用 mod_proxy_wstunnel,如此处所述... https://httpd.apache.org/docs/2.4/mod/mod_proxy_wstunnel.html,会发生什么呢? - Brian Pursley
@bpursley,请仔细阅读问题,我没有任何websocket数据传输,因为我已经禁用了websockets。 - Stepan Yakovenko
你是否意识到检测xhr-polling的唯一方法是使用超时?你只需要知道客户端轮询间隔设置为多少,并将服务器超时设置为比客户端轮询间隔长的时间,这样如果在一段时间内没有看到任何客户端再次轮询,则假定客户端必须已经断开连接。由于轮询的本质,没有一种好的方法可以在所有情况下及时获取断开连接。 - jfriend00
不,可以处理断开连接,在nodejs中,您可以注册此回调函数:req.on('close',function(){console.log("byby")})。即使sockjs内部具有1秒超时或心跳,我也不希望apache将20秒添加到其中。 - Stepan Yakovenko
@StepanYakovenko 你启用了HTTP keep alive吗? - arboreal84
显示剩余7条评论
3个回答

1

您的Apache服务器可能配置了使用 HTTP Keep Alive,这将保持持久连接。在这种情况下,我建议禁用 KeepAlive 或将 KeepAliveTimeout 设置降低到Apache配置中,看看是否解决了问题。

如果这样做不起作用,我还会查看 netstat 并查看每个套接字的状态,并进行根本原因分析。这个 图表 显示了TCP状态机,并可以告诉您每个连接的位置。Wireshark也可以为您提供有关正在发生的情况的一些信息。


@jfriend00 如果你想添加什么内容,请以尊重的方式进行。 - arboreal84
尝试关闭Keepalive以及调整KeepAliveTimeout为10,但没有帮助。此外,如果您查看ProxyPass文档,保持活动选项默认是禁用的。 - Stepan Yakovenko

0
在长轮询中,连接的过程如下所示。
<client> ---> apache ---> <node.js>

当客户端断开连接时

<client> -X-> apache ---> <node.js>

Apache仍然保持连接开放。现在有两种解决方法

ProxyTimeout

您可以将以下内容添加到您的Apache配置中

ProxyTimeout 10

这将在10秒后断开连接,但会每隔10秒断开所有长轮询连接,这是不想要的

Ping

下一个选项是向客户端发送 ping

pingTimeout (数字): 没有 pong 数据包的时间(毫秒)被视为连接已关闭 (60000)

pingInterval (数字): 发送新 ping 数据包之前的时间(毫秒) (25000)

var io = require('socket.io')(server, { 'transports': ['polling'], pingTimeout: 5000, pingInterval: 2500});

上面的代码将确保客户端在离线5秒后断开连接,你可以进一步降低它,但这可能会影响通常的加载场景。
但是阅读所有的帖子、主题和站点后,我不认为你能够复制当直接连接到socket.io时得到的行为,因为socket.io可以轻松地检测到连接中断。

0

20秒的延迟不在Apache代理中。我遇到了同样的问题,本地URL没有延迟,但全局URL有延迟。

这个问题在NodeJs本身中得到了解决。需要从服务器向客户端发送一次性数据以确保其初始化。这个问题在WebSocket插件的文档和问题博客中没有提到。

在服务器接受请求后发送一个虚拟消息,如下所示。

let connection = request.accept(null, request.origin);

connection.on('message', function (evt) {
    console.log(evt);
});

connection.on('close', function (evt) {
    console.log(evt);
});

connection.send("Success"); //dummy message to the client from server

问题是关于SockJS,而不是WebSocket。 - Stepan Yakovenko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接