WebSocket系列之如何建立和維護可靠的連線

黃Java發表於2018-04-05

概述

通過前四篇部落格,相信讀者對於WebSocket的使用和資料(不論是ArrayBuffer還是String)傳輸都有了一個深刻的瞭解。現在我們來介紹下,我在使用WebSocket時,連線相關模組遇到的一些共性問題,以及我們如何解決這些問題。

本文作為WebSocket系列的第五篇文章,它的內容不僅僅限於前端的WebSocket導致的問題,而是結合一整套長連線方案可能遇到的問題來進行說明。其主要內容為:

  • WebSocket建立連線共性問題
  • WebSocket維護連線共性問題

通過這篇部落格,讀者能夠了解在WebSocket線上生產環境遇到的常見連線問題以及對應的解決方案,從而在自己遇到相關問題時可以快速解決。 本文不涉及任何前端WebSocket使用方法或教程,只是作為相關經驗的總結部落格。如果讀者對WebSocket相關使用還沒有具體的認識,可以閱讀前四篇部落格。

建立連線共性問題

如何使用加密的WebSocket(WSS)

如果我們需要使用加密的WebSocket時,我們需要配置證照,以下幾點需要注意:

  • WebSocket地址不能使用IP,必須使用域名。因為證照是針對域名來進行配置的。
  • 證照必須符合新Chrome規範,否則會出現NET::ERR_CERT_COMMON_NAME_INVALID錯誤,具體詳情見Chrome幫助。如果重新簽署後海是出現此問題,需要按下證照中的DNS地址是否包含使用的域名。
  • 如果是開發環境的自簽證照,需要配置到本地證照庫中,否則會出現NET::ERR_CERT_AUTHORITY_INVALID錯誤。

不支援WebSocket的環境下如何降級

部分IE或者低版本Android手機的瀏覽器環境不支援WebSocket,同時Firefox38-41的部分版本WebSocket也不支援傳輸ArrayBuffer資料。因此,在出現不支援WebSocket或者WebSocket連線失敗的情況時,我們需要制定相關的降級策略:

  • 根據瀏覽器進行判斷,如果是不支援WebSocket的瀏覽器或者低版本Android的WebView,直接切換到長輪詢方案。
  • 如果WebSocket連線失敗(初始化後立即觸發了close事件),則立即降級到長輪詢方案。

維持連線共性問題

如何維持長連線不斷開

當前瀏覽器對WebSocket建立的長連線都有節能策略,即持續一段時間內沒有資料傳輸時,瀏覽器會主動斷開長連線,根據當前測試的資料(僅供參考)來看,Chrome瀏覽器的主動斷開時間為300秒左右,而Firefox在120秒左右。

因此,我們如果需要維持長連線長時間不斷開,需要設計特定的心跳來維持這條WebSocket連線。在一個特定的時間間隔中,客戶端向後端傳送一條資料,同時後端也回覆相關的資料(後端回覆是用來檢測網路和後端是否正常工作)。

我目前使用的心跳間隔為45秒,即間隔45秒就像後端傳送一個心跳包。當然,這個時間和相關的後端服務設定以及應用場景相關。

與此同時,後端服務的Nginx中也有相關的長連線維持時長設定。如果你遇到前端建立的WebSocket連線在間隔比較短的時間就被後端主動斷開(即觸發close事件),而前端沒有觸發任何關閉操作,可以檢查下後端相關的時間配置項。在生產環境中,我遇到過由於Nginx的配置引數proxy_read_timeout時間設定小於心跳間隔導致的後端主動斷開連線。

如何處理斷網或者後端異常情況

在瀏覽器網路斷開的情況下,WebSocket是不會收到任何的事件的。由於WebSocket在斷網時的表現和線上時無訊息收發的狀態無法區分,我們需要用其他的方法來進行判斷和區分。具體的方法有如下幾種:

  • 使用心跳包。我們在傳送心跳包後,會收到相關的返回資料。如果我們無法收到此資料,就認為目前網路或者後端異常。
  • offline事件。瀏覽器會在斷網後給頁面傳送一個offline事件(不準確,可以作為參考),我們可以根據此事件來斷開長連線,對使用者進行相關提示。

如何快速的恢復連線

根據上面的操作方案,我們會在網路異常時斷開連線。但是,當網路恢復時,我們需要快速的恢復長連線。我們可以根據以下幾個方案,來恢復我們的WebSocket連線。

  • 遞增重試的時長。當我們短卡網路時,我們立即設定一個遞增的時長(如[1,2,3,5,10,20]秒)來嘗試恢復長連線。
  • online事件重置重試的時長。在瀏覽器網路恢復時,會傳送一個online事件(同樣不準確)。在監聽到online事件時,我們只需要重置這個時長,立即嘗試恢復即可(因為online事件觸發時,網路仍然有可能處於抖動狀態)。
  • 檢測休眠重置重試的時長。當瀏覽器休眠時,JavaScript不會執行。當電腦被喚醒時,如果online事件沒有觸發,那麼重試的時長有可能由於多次嘗試變成一個較大的值。因此我們在檢測到休眠被喚醒後,需要立即重置重試的時長。具體方法為:設定一個setInterval,每次判斷上次執行與本次執行時長間隔。因為休眠時JavaScript不會執行,因此,如果間隔時長較大(超過設定閾值),我們就認為電腦休眠被喚醒了。

總結

本文通過總結我線上上生產環節中遇到的WebSocket相關的連線問題,給大家提供一些經驗的總結合參考。

如果大家遇到相關的問題或者難題,可以根據上面方案進行嘗試,同時也歡迎留言或者私信進行探討。

相關文章