通信技術:SSE設計方案(一)--- 前端Server-Sent Events概念講解和基礎類庫完善發布

同步更新博客:通信技術: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上的東西做測試,地址:github.com/GerryIsWarri不要忘記點顆star支持我,至少得到了你的認可,我會繼續研究下去。

  • js-ommon:為一般開發使用,直接引入js文件的
  • js-node:為node代碼,做簡易伺服器用的
  • js-npm:發的npm打包代碼,可npm i sse-js / yarn add sse-js 安裝
  • index.html:為測試html頁面

總結:

這篇博客主要講解sse技術的基礎概念,因為基礎概念比較多,如果和第二版本一起搞上去,博文肯定很多很多,沒有耐心看下去了,所以這個博文只是讓大家對這個概念有所了解,知道這個東西是什麼,能做什麼,有啥新奇的玩意,能解決項目的什麼問題。當然,我既然研究這個技術,當然為了保證將這個類庫寫好,至少可以到生產上使用這個類庫,當然這個路不是那麼好走的,還需要不停的去研究和改正。正如我正在走的開發的路,都要我們一步一個腳印的去走的,共勉。

夜已深,大家晚安,明天發表這個博客...


推薦閱讀:

項目代碼調試:提問前要做的六個步驟
帶你了解前端開發
精讀《如何安全地使用 React context》
ES6--擴展運算符與剩餘操作符

TAG:前端开发 | 通信 | 设计思想 |