【问题标题】:Socket.io receives messages before browser navigates to new pageSocket.io 在浏览器导航到新页面之前接收消息
【发布时间】:2012-08-20 10:44:10
【问题描述】:

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

我现在看到的是这样的:

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

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

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

【问题讨论】:

    标签: javascript node.js websocket socket.io


    【解决方案1】:

    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

    使用基本的 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 会话中删除通知队列。

    【讨论】:

    • 现在我正在实现自己的用户级会话管理。我知道每个连接的不同会话 ID,并且,正如我上面提到的,当新连接通过身份验证时,我断开所有旧连接。听起来您对.emit 回调的建议将是最容易实现的,尽管我有点担心会在页面重新加载之前调用回调。有可能延迟吗?
    • 这样看:如果你是作为表单提交的结果发送通知,在你想发送通知的那一刻,旧的套接字连接已经没有了,并且赢了在响应被发送到浏览器之前,它不是一个新的连接。因此,您需要一种在 Socket.io 上层将消息排队的方法;用户会话是这样做的自然场所。
    【解决方案2】:

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-01
      相关资源
      最近更新 更多