簡介
HTML 5 Server Send Event (SSE) 是一種將資料從伺服器端推送到瀏覽器端的技術。與 Ajax polling 這種多次發送 HTTP 請求的的方式相比,SSE 只需要一次的 HTTP 請求,因此能減少連線次數及傳輸的資料量、降低伺服器的負擔,並讓使用者得到更即時的資訊。
而與 Web Socket 相較,它沿用 HTTP 協定,不需要再額外建立專門處理其他協定的伺服端程式,直接沿用原本的網頁伺服器(如:Apache, Nginx)即可。所以無論是在程式開發上還是維運管理上都要簡易很多。
因此,如果只需要單向的從伺服器到瀏覽器的推送,就不需要使用 Web Socket,可以只使用 SSE。接續 Redis Notification 中提到的 Redis 通知 PHP 程式的技術,本篇將展示如何使用 SSE 將 Redis 的更新同步到瀏覽器,並使用 ECMAScript 2015 的新功能來組織程式。
HTML5 Server Send Event (SSE)
實作 SSE 有三個要點,首先是伺服器端的網頁程式必須要發送 SSE 專屬的內容類型,然後是傳輸的內容必須依照 SSE 的格式撰寫,最後是瀏覽器接收到訊息後的處理。
伺服器端 PHP 程式範例
|
|
資料格式
SSE 的每個訊息由以下欄位構成:
event - 如果該訊息是一個事件通知,則此欄位代表事件的名稱,非必要欄位。
data - 訊息的資訊,必要欄位,一個訊息可以有多個 data 欄位。
id - 指定訊息的 id,可以讓接收者辨識目前的訊息,以便了解當前接收進度,非必要欄位。
retry - 指定從該訊息後,當瀏覽器斷線時,重新連接的間格時間,單位是毫秒,非必要欄位。
其中每個欄位以一個換行符號 \n 分隔,而每個訊息最後以兩個換行符號分隔。
範例:
瀏覽器端程式範例
|
|
詳細的 EventSource 用法可參考 Using server-sent events
Redis Notification 即時顯示
在 Redis Notification 中展示了將 Redis 的異動通知 PHP 程式的技術,現在要應用 SSE 進一步將異動傳達給客戶端。
首先將伺服器端的程式 notify.php 改寫為可以發送 SSE 訊息的程式,將原本的輸出轉換成 SSE 格式並停用輸出緩衝,還要注意 Web Server 如果會緩衝輸出也要先停用。
改寫後的程式 getUpdates.php 如下:
為了要讓後來連線的程式能 follow 目前最新的結果,需要有一隻程式 getProductList.php 可以顯示目前最新的產品清單如下:
|
|
現在可以開始寫瀏覽器端的程式了,需要的程式檔案列表如下:
file name | description |
---|---|
main.js | 負責整合各部分程式碼並操作 DOM |
ProductList.js | 負責管理商品清單的資料 |
ProductListException.js | 代表 ProductList 發生異常的物件 |
ServerSendEventHandler.js | 負責處理產品清單異動的事件 |
ServerSendEventHandlerException.js | 代表 ServerSendEventHandler 發生異常的物件 |
main.js:
ProductList.js:
ProductListException.js:
ServerSendEventHandler.js:
ServerSendEventHandlerException.js:
為了讓 ECMAScript 2015 的程式碼能夠順利在瀏覽器上執行,我使用了 Babel 和 webpack 將這些 js 轉成 ECMAScript 5 並整合成一個 bundle.js 檔案給 main.html 載入。
最後的主要進入頁面如下 main.html:
整個專案的程式可以在 GitHub下載。
開始測試
首先在 Redis 插入起始資料:
進入頁面:
在 Redis 新增資料:
查看頁面:
在 Redis 修改資料:
查看頁面:
在 Redis 刪除資料:
查看頁面:
小結
沿續了 Redis Notification 一文中關於 Redis 推送資料的範例,本篇進一步使用 SSE 將此資料異動通知給瀏覽器,並且嘗試使用 ES 20015 來進行開發。從測試結果可以看到 SSE 確實能即時通知瀏覽器最新的資訊。
雖然 SSE 可以沿用網頁伺服器而不需要自行開發伺服器程式,但是對於 SSE 的運作原理還是要有足夠深入了解,才能了解應該如何設定網頁伺服器,並且注意到許多安全性以及系統架構上的問題。
在投入正式產品環境之前,還是要再經過謹慎的評估和測試才能運用。