好了,開篇還是要扯扯的,否則感覺這個技術講的么有那么凍人,嗯,這個晚上是有點冷了,秋衣秋褲大家都該加起來了,反正我不幫你買,妹子除外,嘻嘻。
之前幾篇博客,研究前端通信技術的第一層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技術的基礎概念,因為基礎概念比較多,如果和第二版本一起搞上去,博文肯定很多很多,沒有耐心看下去了,所以這個博文只是讓大家對這個概念有所了解,知道這個東西是什么,能做什么,有啥新奇的玩意,能解決項目的什么問題。當然,我既然研究這個技術,當然為了保證將這個類庫寫好,至少可以到生產上使用這個類庫,當然這個路不是那么好走的,還需要不停的去研究和改正。正如我正在走的開發的路,都要我們一步一個腳印的去走的,共勉。
夜已深,大家晚安,明天發表這個博客...