4

我遇到了 Socket.io 在页面导航发生之前接收消息的问题 - 通常当消息是导航触发的某些服务器端操作的直接结果时。

我现在看到的是这样的:

  1. Socket.io 连接
  2. 用户触发页面导航(提交表单、刷新等)
  3. 服务器端逻辑向 socket.io 服务器发送请求,该服务器立即将事件分派给仍然连接的客户端
  4. 客户端接收并确认请求(我很确定socket.io内置了一些消息确认,如果我错了,请纠正我),并向用户显示通知,但随后......
  5. socket.io 连接在原始页面上关闭
  6. 新页面加载并显示
  7. Socket.io 打开一个新连接,但没有新消息,因为最后一个已收到并确认。

这本身并不是一个真正的错误,因为我认为期望 Socket.io 在导航发生之前关闭连接是不合理的。但是,我不确定处理此问题的最佳方法是什么。目前,我一次为每个客户端打开一个连接,并在新连接时关闭另一个。但是在这种情况下不会发生这种情况,因为第一个在第二个连接之前已经关闭。我也可以保留所有客户端的列表,但这也不能解决这个问题,因为第一个连接仍然会收到消息。

有人可以建议解决此问题的方法,以确保用户始终看到消息通知吗?

4

2 回答 2

4

Socket.io 使用自己的会话 ID 跟踪逻辑连接。如果您在客户端连接时查看控制台,您将看到 ID:

info  - handshake authorized Q9syoIK47JI7dACYpxiA

重要的是要理解这些 ID 是按页面的,并且与 HTTP 会话完全分开。Socket.io 客户端库只是将其会话 ID 保存在 JavaScript 变量中。因此,在导航时,ID显然丢失了。

因此,在导航时,会发生这种情况:

  1. 用户在连接到 sio session 的页面上1
  2. 我们开始导航到新页面。On window.onbeforeunload,Socket.io发起一个同步 XHR 请求,告诉服务器它正在断开连接。如果成功,则会话 ( 1) 立即终止;否则,会话最终将超时。
  3. 加载了一个新页面。它将连接到 Socket.io 服务器并被分配一个新的会话 ID 2,.
  4. 由于我们的客户端现在已连接到 session ,因此您发送到 session 的任何内容1显然都不会被传递2

使用基本的 Socket.io 功能,无法区分在页面之间导航的用户和新用户。无论哪种情况,用户都将连接到一个新的 Socket.io 会话。

如果不确切知道您的应用程序是如何工作的或您想要完成什么,就很难给出解决问题的明确建议。

最有可能的是,您需要做的是将 Socket.io 会话与用户的HTTP 会话相关联。您可以将通知存储在用户会话中的队列中,并在显示时将其删除。有两种方法可以做到这一点:

  • 由于您正在执行整页加载,因此您可以使用页面本身直接向下发送排队通知。成功渲染后删除队列。
  • 在新的 Socket.io 连接上,通过套接字发送未读通知。 提供.emit一个回调函数——这是 Socket.io 为您提供的交付确认。确认交付后,您可以从用户的 HTTP 会话中删除通知队列。
于 2012-08-24T22:52:21.460 回答
-1

最简单的解决方案:使用onbeforeunload事件断开 socket.io。

我使用 HTTP 调试器验证了此事件在浏览器发出请求之前触发(至少在 Chrome 中),因此如果 socket.io 在此处断开连接,它将不会收到任何用于下一页的消息。

window.onbeforeunload = function() {
    socket.disconnect();
};

我没有在多个浏览器中测试过这个,所以它可能不是一个完美的解决方案,但它现在似乎解决了这个问题。

于 2012-08-27T22:52:39.003 回答