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

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

我现在看到的是这样的:

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

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

有人可以build议解决这个问题,以确保用户总是看到通知消息?

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

info - handshake authorized Q9syoIK47JI7dACYpxiA 

重要的是要明白这些ID是每个页面 ,并完全独立于HTTP会话 。 Socket.io客户端库只是将其会话ID保存在JavaScriptvariables中。 所以在导航的时候,身份certificate显是丢失了。

所以,在导航时,会发生这种情况:

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

使用基本的Socket.iofunction,不可能区分在页面之间导航的用户和新用户。 在这两种情况下,用户都将连接到一个新的Socket.io会话。

不知道你的应用程序是如何工作的或者你想要完成什么,很难给出一个明确的build议来解决你的问题。

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

  • 由于您正在进行整页加载,因此您可以直接向页面本身发送排队的通知。 成功呈现时删除队列。
  • 在新的Socket.io连接上,通过套接字发送未读通知。 提供.emitcallback函数 – 这是Socket.io为您提供的交付确认。 交付确认后,您可以从用户的HTTP会话中删除通知队列。

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

我使用HTTPdebugging器validation了此事件在浏览器发出请求之前触发(至less在Chrome中),所以如果socket.io在此处断开连接,则不会收到任何用于以下页面的消息。

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

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