Java服務端推送消息有那麼難嗎?

2019-08-28     Java架構人生

原文地址:https://dwz.cn/FFB05DFg

作者:碼農小胖哥

場景:

今天項目經理交給我一個開發任務。如果有人在前台下了訂單就給後台倉庫管理一個髮貨通知。也就是服務端觸發一個事件,推送消息到客戶端。

如果我用websocket來做還要搞個websocket伺服器,而且還 有不少配置。websocket是全雙工通信,單向通信簡直是殺雞用牛刀。用輪詢吧,浪費伺服器資源不說,還不一定實時,訂單處理慢了豈不是怠慢了客戶。有沒有別的選擇呢?當然有!

1.SSE推送技術

SSE全稱Server-sent Events,是HTML 5 規範的一個組成部分,具體去MDN網站查看相關文檔。該規範十分簡單,主要由兩個部分組成:第一個部分是伺服器端與瀏覽器端之間的通訊協議,第二部分是在瀏覽器端可供 JavaScript 使用的 EventSource 對象。通訊協議是基於純文本的簡單協議。伺服器響應的內容類型是「text/event-stream」。響應文本的內容可以看成是一個事件流,由不同的事件所組成。每個事件由類型和數據兩部分組成,同時每個事件可以有一個可選的標識符。不同事件的內容之間通過僅包含回車符和換行符的空行(「\\r\\n」)來分隔。每個事件的數據可能由多行組成。

如上圖所示,每個事件之間通過空行來分隔。每一行都是由鍵值對組成。如果鍵為空則表示該行為注釋,會在處理時被忽略。例如第10行。

第1行表示一個只包含數據的事件。會按照默認事件走(message事件)。第3-4行代表一個附帶eventID的事件。第6-8行代表一個自定義事件。第10-14行代表一個多行數據事件,多行數據由換行符連結

key定義有以下幾種:

  • data,表示該行包含的是數據。以 data 開頭的行可以出現多次。所有這些行都是該事件的數據。
  • event,表示該行用來聲明事件的類型。瀏覽器在收到數據時,會產生對應類型的事件。默認提供三個標準事件(當然你可以自定義):

  • id,表示該行用來聲明事件的標識符。伺服器端返回的數據中包含了事件的標識符,瀏覽器會記錄最近一次接收到的事件的標識符。如果與伺服器端的連接中斷,當瀏覽器端再次進行連接時,會通過 HTTP 頭「Last-Event-ID」來聲明最後一次接收到的事件的標識符。伺服器端可以通過瀏覽器端發送的事件標識符來確定從哪個事件開始來繼續連接。
  • retry,表示該行用來聲明瀏覽器在連接斷開之後進行再次連接之前的等待時間。

SSE只適用於高級瀏覽器,但是注意IE不直接支持。IE上的XMLHttpRequest對象不支持獲取部分的響應內容,所以不支持。每次總有IE,怪不得快被淘汰了。

2.SSE VS Websocket

  • SSE 只能Server到Client單項,而Websocket是雙向通信。
  • SSE 比 Websocket 輕量。當然功能要簡單的多。開發便利,不牽涉協議升級問題。
  • SSE 天然支持斷線重連

3.Spring Mvc中的SSE

Spring Mvc對SSE進行了支持。如果你要聲明一個SSE連接。只需要在你的控制器聲明一個如下接口:

必須必須返回SseEmitter對象,SseEmitter對象是Session級別的,如果你要點對點針對每個session要獨立存儲。如果你是廣播可以共用一個SseEmitter對象。按照SSE規範也必須聲明produces為"text/event-stream"。當你調用該接口的時候將建立起SSE連接。

你可以在另一個線程中調用SseEmitter的send方法向客戶端發送事件。你也可以在發送事件後調用complete方法來關閉SSE連接。

4.瀏覽器端的EventSource

由於SSE 是HTML5規範。所以對於APP端必須有HTML才能支持。並且IE如果要支持需要使用一些兼容開發包,比如polyfill庫。客戶端因為只接受事件所以開發比較簡單:

  • 聲明客戶端連接, 初始化EventSource對象。
  • 編寫監聽器來監聽事件。

今天介紹了SSE 服務端推送。和長輪訓、comet、websocket相比而言比較輕量級。在一些需要伺服器實時推送規模不大的業務場景實現更簡單點。相信看了本文後你會很快入門。在實際開發中要根據業務對這幾種推送進行技術選型。沒有最好的只有最適合的。SSE對大多數開發者來說不夠熟悉。

文章來源: https://twgreatdaily.com/zh-tw/2-XI12wBJleJMoPMvEon.html