2012-08-24 27 views
4

我在使用Socket.io接收消息時遇到了頁面導航之前的問題 - 通常是消息是由某個服務器端操作觸發的直接結果導航。Socket.io在瀏覽器導航到新頁面之前接收消息

我所看到的,現在看起來是這樣的:

  1. Socket.io連接
  2. 用戶觸發頁面導航(提交一個表單,刷新等)
  3. 服務器端邏輯向socket.io服務器發送請求,該請求立即將事件分派給仍然連接的客戶端
  4. 客戶端接收並確認請求(我確信有一些socket.io內置消息的確認,糾正我,如果我錯了),並會顯示通知用戶,但隨後...
  5. 的socket.io連接關閉原來的頁面
  6. 新的頁面加載和顯示
  7. Socket.io打開一個新的連接上,但沒有新的消息,因爲上次一個被收到並確認。

這實際上並不是一個錯誤,因爲我不認爲期望Socket.io在發生導航之前關閉連接是不合理的。但是,我不確定處理這個問題的最好方法是什麼。目前,我一次保持每個客戶端打開一個連接,並在新連接時關閉另一個連接。這種情況在這種情況下不會發生,因爲第一個在第二個連接之前已經關閉。我也可以保留所有客戶端的列表,但這也不能解決這個問題,因爲消息仍然會被第一個連接接收。

有人可以建議解決這個問題,以確保用戶總是看到通知的消息?

回答

4

Socket.io使用自己的會話ID跟蹤邏輯連接。如果你看控制檯當客戶端連接,您將看到的ID:

info - handshake authorized Q9syoIK47JI7dACYpxiA 

什麼重要的是要明白的是,這些ID是每頁,並從HTTP會話完全分開的。 Socket.io客戶端庫僅將其會話標識保存在JavaScript變量中。因此,在導航時,ID顯然丟失了。

所以,在導航,出現這種情況:

  1. 用戶連接到SIO會議1在頁面上。
  2. 我們開始導航到新頁面。在window.onbeforeunload上,Socket.io initiates a synchronous XHR request告訴服務器它正在斷開連接。如果成功,會議(1)立即終止;否則,會話將最終超時。
  3. 加載新頁面。它將連接到Socket.io服務器並被分配一個新的會話ID,2
  4. 因爲我們的客戶現在連接到會話2,所以您發送至會話1的任何內容顯然都不會發送。

使用基本的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會話中刪除通知隊列。
+0

現在我正在實現我自己的用戶級會話管理。我知道每個連接的不同會話ID,正如我上面提到的,當新連接進行身份驗證時,我斷開了所有舊連接。聽起來像你的建議,'.emit'的回調將是最容易實現的,儘管我有點擔心回調將在頁面重新載入前被調用。這是否有可能延遲? – robbles

+0

這樣看待:如果您是通過表單提交發送通知的,那麼在您想發送通知的時刻,舊的套接字連接已經消失,並且不會有新連接,直到在響應被髮送到瀏覽器之後。因此,您需要一種在Socket.io上方排列消息的方法;用戶會話是自然而然的事情。 – josh3736

-1

最簡單的解決方案:使用onbeforeunload事件斷開socket.io。

我使用HTTP調試器驗證了此事件在瀏覽器發出請求(至少在Chrome中)之前觸發,因此如果socket.io在此處斷開連接,它將不會收到任何用於以下頁面的消息。

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

我沒有在多個瀏覽器測試這一點,所以它可能不是一個完美的解決方案,但它似乎能解決這個問題了。

相關問題