Socket.io在浏览器导航到新页面之前接收消息

时间:2012-08-24 21:08:17

标签: javascript node.js websocket socket.io

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

我现在看到的是这样的:

  1. Socket.io连接
  2. 用户触发页面导航(提交表单,刷新等)
  3. 服务器端逻辑向socket.io服务器发送请求,该服务器立即将事件分派给仍连接的客户端
  4. 客户端接收并确认请求(我非常确定有一些内置于socket.io的消息确认,如果我错了就纠正我),并会向用户显示通知,但随后。 ..
  5. socket.io连接在原始页面上关闭
  6. 新页面加载并显示
  7. Socket.io打开一个新连接,但没有新消息,因为最后一个消息已被接收并确认。
  8. 这本身并不是一个错误,因为我不认为期望Socket.io在导航发生之前关闭连接是合理的。但是,我不确定最好的办法是什么。目前,我每个客户端一次打开一个连接,并在新连接时关闭另一个连接。但是,在这种情况下不会发生这种情况,因为第一个在第二个连接之前已经关闭。我也可以保留所有客户端的列表,但这也不能解决这个问题,因为第一次连接仍然会收到该消息。

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

2 个答案:

答案 0 :(得分:4)

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

info  - handshake authorized Q9syoIK47JI7dACYpxiA

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

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

  1. 用户位于连接到sio会话1的页面上。
  2. 我们开始导航到新页面。在window.onbeforeunload上,Socket.io initiates a synchronous XHR request告诉服务器它正在断开连接。如果成功,会话(1)立即终止;否则,会议最终会超时。
  3. 正在加载新页面。它将连接到Socket.io服务器并分配一个新的会话ID 2
  4. 您发送到会话1的任何内容显然都不会发送,因为我们的客户现已连接到会话2
  5. 使用基本的Socket.io功能,无法区分在页面之间导航的用户和新用户。在任何一种情况下,用户都将连接到新的Socket.io会话。

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

    最有可能的是,您需要做的是associate a Socket.io session with the user's HTTP session。您可以将通知存储在用户会话的队列中,并在显示时删除它们。有两种方法可以做到这一点:

    • 由于您正在进行整页加载,因此您可以直接向页面本身发送排队通知。成功渲染后删除队列。
    • 在新的Socket.io连接上,通过套接字发送未读通知。 Give .emit a callback function - 这是Socket.io为您提供的交付确认。确认传递后,您可以从用户的HTTP会话中删除通知队列。

答案 1 :(得分:-1)

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

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

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

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