通信技術:SSE設計方案(一)--- 前端Server-Sent Events概念講解和基礎類庫完善釋出
好了,開篇還是要扯扯的,否則感覺這個技術講的麼有那麼凍人,嗯,這個晚上是有點冷了,秋衣秋褲大家都該加起來了,反正我不幫你買,妹子除外,嘻嘻。
之前幾篇部落格,研究前端通信技術的第一層ajax技術,從最基礎的東西開始開發相容,然後到最近的1.6版本吧,前前後後幾乎将ajax的所有能用的技術都研究過一遍了,在github上也得到了120+的star,在這裡我要感謝大家的支援。主要這裡為什麼會這樣說呢,因為之前得到大家的認可和鼓勵,是以這次将進行前端通信技術的第二個階段的研究了,也就是前端的伺服器推送 --- Server-Sent Events技術的研究。夜深了,不扯太多廢話了,我們直接進入主題。
概念講解:
Server-Sent Events:簡稱SSE技術,也是前端es5支援的一種基于http協定的伺服器推送技術。
EventSource:js中承載SSE技術的主要核心方案和方法
單工通道:隻能一方面的資料導向,例如,在我們前端,我們通過浏覽器向伺服器請求資料,但是伺服器不會主動推送資料給我們,這就是單通道
雙工通道:類似webSocket這樣的技術,用戶端可以推資料給伺服器,伺服器也可以推資料給用戶端(下個版本實作)
定點推送:伺服器可以将資料針對單個用戶端推送(下個版本實作)
多人推送:伺服器可以将資料一次性推送給所有人(下個版本實作)
相容性(看下圖):

在所有IE系列中都不支援,其他浏覽器幾乎都可以實作,是以為了實作萬惡的IE,會有如下2種方案
- 在其他浏覽器上使用原生 EventSource 對象,而在 IE 上則使用簡易輪詢或 COMET 技術來實作;
- 使用 polyfill 技術,即使用第三方提供的 JavaScript 庫來屏蔽浏覽器的不同。本文使用的是 polyfill 技術,隻需要在頁面中加載第三方 JavaScript 庫即可。應用本身的浏覽器端代碼并不需要進行改動。
是以,這個方案,我會在最後一個版本和部落格專門做相容,暫時我們就忽略這個相容性問題
對于其他通信技術的比較(也就是什麼時候做這樣的技術選型)
- sse是基于http協定的,對于現有項目的改造和支援是成本最低的方案。webSocket需要前後端全都換上新的協定支援
- 對于推送的頻率來說,針對小于1次/1的推送,sse的使用最合适。大于1次的使用不劃算,建議webSocket(考慮成本)
- WebSocket 技術也比較複雜,包括伺服器端和浏覽器端的實作都不同于一般的 Web 應用。
- 對于輪詢來說的話,每次的http協定的建立和銷毀對性能有點要求,況且對這個輪詢的時間點也不是能特别好的把握
so,sse隻是針對在适合他的地方才是最好的,這些點為大家做技術選型做些參考。
用戶端(浏覽器)技術講解:
在用戶端,也就是浏覽器中,承載這個技術的就是EventSource了,下面直接上代碼吧
// 通用方案
create:function (options) { // option為可配置參數
var param = tool.initParam(options),sendData = \'\'; // 将使用者參數和預設參數合并
if (param.data){ // 判斷是否傳遞參數給伺服器,做參數處理
tool.each(param.data, function (item, index) {
sendData += (index + "=" + item + "&")
});
sendData = sendData.slice(0, -1);
}
var es = new EventSource(param.url+\'?\'+sendData); //建立EventSource連結
es.addEventListener(\'open\',function (e) { // 注冊預設open事件
param.openEvent(e)
});
es.addEventListener(\'message\',function (e) { // 注冊預設message事件,如果伺服器不指定回掉,則走這個
param.messageEvent(e)
});
es.addEventListener(\'error\',function (e) { // 注冊預設error事件
param.errorEvent(e)
});
// 建立使用者自定義事件
if (param.customEvent.length > 0){
tool.each(param.customEvent,function (item) {
es.addEventListener(item.name,item.callback);
})
}
}
當然用戶端還有代表連結狀态的參數es.readyState:
-
- 相當于常量EventSource.CONNECTING,表示連接配接還未建立,或者連接配接斷線。
- 相當于常量EventSource.OPEN,表示連接配接已經建立,可以接受資料。
- 相當于常量EventSource.CLOSED,表示連接配接已斷,且不會重連。
message回調的傳回值(可自己debugger看):
data:伺服器端傳回的資料(文本格式)。
origin: 伺服器端URL的域名部分,即協定、域名和端口。
lastEventId:資料的編号,由伺服器端發送。如果沒有編号,這個屬性為空。
簡單解釋下:通過先new EventSource對象,建立連接配接,然後注冊一些預設事件和自定義事件,就結束了,用戶端就這麼簡單。主要在服務端。
預設參數如下(有些參數預先定義下個版本使用):
var initParam = {
url :\'\', //所連結的伺服器位址
data:\'\', //所發送的用戶端資料
customEvent:[], //自定義事件 格式:[{name:\'事件名稱\',callback:function(res){}}]
withCredentials:false, //是否發送跨域憑證
serverTimeout:60000, //伺服器http預設逾時時間 待考慮:用戶端配置伺服器時間,不安全
clientConnection:3000, //設定浏覽器重連時間,浏覽器預設3s重連,
openEvent:function () {}, //用戶端開始連結的事件
messageEvent:function () {}, //用戶端接受到消息的事件(如不自定義系統預設)
errorEvent:function () {} //用戶端錯誤事件
}
伺服器講解:
對于建立連接配接的伺服器,針對連結的用戶端有如下傳回參數:
:這是注釋 單獨一個冒号,代表伺服器推送的一個注釋。(這個可解決http中的324,發送心跳包)
id:11 代表資料辨別符,代表目前資料的唯一辨別(如果斷線,用戶端會在下次http head中發送這個辨別,可做資料傳輸标記)
data:我是誰 這個資料就是用戶端所接受到的資料(可推送格式化過的json資料)
event:myEvent 伺服器傳回用戶端所執行事件(如不定義預設執行message事件)
retry:3000 用戶端在http逾時斷開後多長時間重新連接配接
對于伺服器的這些參數的互相組合,是不是突然有種腦洞大開的感覺,下個版本将在這些參數中做文章,實作開頭所說的各種花樣技術
對于做測試中發現的許多問題抛出,可能你也會想到,這些問題都将在下幾個版本做完善
- 用戶端相容性問題(這個後面做)
- 用戶端重連時間中,是否會丢失資料
- 伺服器的http協定逾時時間的設定
- 對于連結中出現的伺服器傳回逾時
- 如何做到單點推送,群推送
- 伺服器如何丢棄已斷開的連結
- .......
測試如下(跳過ie系列)
chrome:
火狐:
opera:
safair:暫時沒有mac支援,淡定
所有都上傳github了,可直接拉去github上的東西做測試,位址:https://github.com/GerryIsWarrior/SSE,不要忘記點顆star支援我,至少得到了你的認可,我會繼續研究下去。
js-ommon:為一般開發使用,直接引入js檔案的
js-node:為node代碼,做簡易伺服器用的
js-npm:發的npm打包代碼,可npm i sse-js / yarn add sse-js 安裝
index.html:為測試html頁面
總結:
這篇部落客要講解sse技術的基礎概念,因為基礎概念比較多,如果和第二版本一起搞上去,博文肯定很多很多,沒有耐心看下去了,是以這個博文隻是讓大家對這個概念有所了解,知道這個東西是什麼,能做什麼,有啥新奇的玩意,能解決項目的什麼問題。當然,我既然研究這個技術,當然為了保證将這個類庫寫好,至少可以到生産上使用這個類庫,當然這個路不是那麼好走的,還需要不停的去研究和改正。正如我正在走的開發的路,都要我們一步一個腳印的去走的,共勉。
夜已深,大家晚安,明天發表這個部落格...