成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

服務(wù)端事件EventSource揭秘

sf190404 / 3097人閱讀

摘要:不過永久幀的技術(shù)會導(dǎo)致主頁面的加載條始終處于狀態(tài),體驗很差。同時,規(guī)范允許服務(wù)端指定自定義事件,客戶端偵聽該事件即可。

服務(wù)端推

服務(wù)端推,指的是由服務(wù)器主動的向客戶端發(fā)送消息(響應(yīng))。在應(yīng)用層的HTTP協(xié)議實現(xiàn)中,“請求-響應(yīng)”是一個round trip,它的起點來自客戶端,因此在應(yīng)用層之上無法實現(xiàn)簡易的服務(wù)端推功能。當(dāng)前解決服務(wù)端推送的方案有這幾個:

客戶端長輪訓(xùn)

websocket雙向連接

iframe永久幀

長輪訓(xùn)雖然可以避免短輪訓(xùn)造成的服務(wù)端過載,但在服務(wù)端返回數(shù)據(jù)后仍需要客戶端主動發(fā)起下一個長輪訓(xùn)請求,等待服務(wù)端響應(yīng),這樣仍需要底層的連接建立而且服務(wù)端處理邏輯需要相應(yīng)處理,不符合邏輯上的流程簡單的服務(wù)端推送;

websocket連接相對而言功能最強大,但是它對服務(wù)器的版本有要求,在可以使用websocket協(xié)議的服務(wù)器上盡量采用此種方式;

iframe永久幀則是在在頁面嵌入一個專用來接受數(shù)據(jù)的iframe頁面,該頁面由服務(wù)器輸出相關(guān)信息,如,服務(wù)器不停的向iframe中寫入類似的script標(biāo)簽和數(shù)據(jù),實現(xiàn)另一種形式的服務(wù)端推送。不過永久幀的技術(shù)會導(dǎo)致主頁面的加載條始終處于“l(fā)oading”狀態(tài),體驗很差。

HTML5規(guī)范中提供了服務(wù)端事件EventSource,瀏覽器在實現(xiàn)了該規(guī)范的前提下創(chuàng)建一個EventSource連接后,便可收到服務(wù)端的發(fā)送的消息,這些消息需要遵循一定的格式,對于前端開發(fā)人員而言,只需在瀏覽器中偵聽對應(yīng)的事件皆可。

相比較上文中提到的3中實現(xiàn)方式,EventSource流的實現(xiàn)方式對客戶端開發(fā)人員而言非常簡單,兼容性上出了IE系的瀏覽器(IE、Edge)外其他都良好;對于服務(wù)端,它可以兼容老的瀏覽器,無需upgrade為其他協(xié)議,在簡單的服務(wù)端推送的場景下可以滿足需求。在瀏覽器與服務(wù)端需要強交互的場景下,websocket仍是不二的選擇。

EventSource規(guī)范簡析 瀏覽器端

瀏覽器端,需要創(chuàng)建一個EventSource對象,并且傳入一個服務(wù)端的接口URI作為參數(shù)。

var evtSource = new EventSource("http://localhost:9111/es");

其中,"http://localhost:9111/es"為服務(wù)端吐出數(shù)據(jù)的接口。目前,EventSource在大多數(shù)瀏覽器端不支持
跨域,因此它不是一種跨域的解決方案。

默認(rèn)EventSource對象通過偵聽“message”事件獲取服務(wù)端傳來的消息,“open”事件則在http連接建立后觸發(fā),”error“事件會在通信錯誤(連接中斷、服務(wù)端返回數(shù)據(jù)失?。┑那闆r下觸發(fā)。同時,EventSource規(guī)范允許服務(wù)端指定自定義事件,客戶端偵聽該事件即可。

evtSource.addEventListener("message",function(e){
    console.log(e.data);
});
evtSource.addEventListener("error",function(e){
    console.log(e);
})
服務(wù)端

事件流的對應(yīng)MIME格式為text/event-stream,而且其基于HTTP長連接。針對HTTP1.1規(guī)范默認(rèn)采用長連接,針對HTTP1.0的服務(wù)器需要特殊設(shè)置。

服務(wù)端返回數(shù)據(jù)需要特殊的格式,它分為四種消息類型:

event, data, id, retry

其中,event指定自定義消息的名稱,如event: customMessagen;

data指定具體的消息體,可以是對象或者字符串,如data: JSON.stringify(jsonObj) ,在消息體后面有兩個換行符n,代表當(dāng)前消息體發(fā)送完畢,一個換行符標(biāo)識當(dāng)前消息并未結(jié)束,瀏覽器需要等待后面數(shù)據(jù)的到來后再觸發(fā)事件;

id為當(dāng)前消息的標(biāo)識符,可以不設(shè)置。一旦設(shè)置則在瀏覽器端的eventSource對象中就會有體現(xiàn)(假設(shè)服務(wù)端返回id: 369n),eventSource.lastEventId == 369。該字段使用場景不大;

retry設(shè)置當(dāng)前http連接失敗后,重新連接的間隔。EventSource規(guī)范規(guī)定,客戶端在http連接失敗后默認(rèn)進(jìn)行重新連接,重連間隔為3s,通過設(shè)置retry字段可指定重連間隔;

每個字段都有名稱,緊接著有個”:“。當(dāng)出現(xiàn)一個沒有名稱的字段而只有”:“時,這就會被服務(wù)端理解為”注釋“,并不會被發(fā)送至瀏覽器端,如: commision。

由于EventSource是基于HTTP連接之上的,因此在一段沒有數(shù)據(jù)的時期會出現(xiàn)超時問題。服務(wù)器默認(rèn)HTTP超時時間為2分鐘,在node端可以通過response.connection.setTimeou(0)設(shè)置為默認(rèn)的2min超時, 因此需要服務(wù)端做心跳保活,否則客戶端在連接超時的情況下出現(xiàn)net::ERR_INCOMPLETE_CHUNKED_ENCODING錯誤。通過閱讀相關(guān)規(guī)范,發(fā)現(xiàn)注釋行可以用來防止連接超時,服務(wù)器可以定期發(fā)送一條消息注釋行,以保持連接不斷。

下面提供koa的服務(wù)端代碼:

var fs = require("fs");
var path = require("path");
var PassThrough = require("stream").PassThrough;
var Readable = require("stream").Readable;
var koa = require("koa");
var Router = require("koa-router");
var app = new koa();
var router = new Router();

function RR(){
    Readable.call(this,arguments);
}
RR.prototype = new Readable();
RR.prototype._read = function(data){
}

router.get("/",function(ctx,next){
    ctx.set("content-type","text/html");
    ctx.body = fs.readFileSync(path.join(process.cwd(),"eventServer.html"));
});

const sse = (stream,event, data) => {
    return stream.push(`event:${ event }
data: ${ JSON.stringify(data) }

`)
//    return stream.write(`event:${ event }
data: ${ JSON.stringify(data) }

`);
}
router.get("/es",function(ctx,next){
    var stream = new RR()//PassThrough();
    ctx.set({
        "Content-Type":"text/event-stream",
        "Cache-Control":"no-cache",
        Connection: "keep-alive"
    });
    sse(stream,"test",{a: "yango",b: "tango"});
    ctx.body = stream;
    setInterval(()=>{
        sse(stream,"test",{a: "yango",b: Date.now()});
    },3000); 
});

app.use(router.routes());
app.listen(9111,function(){
    console.log("listening port 9111");
});

此處需要注意的是koa-router的返回值必須是一個Stream(Readable),這是由于koa的特殊性造成的。如果context.body不是Stream是一個字符串或者Buffer實例,會直接在node原生中調(diào)用res.end(buffer),結(jié)束了HTTP響應(yīng):

koa lib/application.js

// responses
if (Buffer.isBuffer(body)) return res.end(body);
if ("string" == typeof body) return res.end(body);
if (body instanceof Stream) return body.pipe(res);

因此造成了服務(wù)端事件流無法正確響應(yīng)。而返回Stream類型的方式有幾種,如通過擴(kuò)展stream模塊的Readable可讀流返回或者直接采用PassThrough流返回,亦可通過through2模塊或者Transform對象實現(xiàn),歸根到底保證可以從該stream對象中pipe出數(shù)據(jù)至http.ServerResponse對象中。

附頁面代碼






    
hello world

參考資料

使用服務(wù)器發(fā)送事件
EventSource超時

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/89422.html

相關(guān)文章

  • SSE eventSource簡介

    eventSource簡單介紹 eventSource是用來解決web上服務(wù)器端向客戶端推送消息的問題的。不同于ajax輪詢的復(fù)雜和websocket的資源占用過大,eventSource(sse)是一個輕量級的,易使用的消息推送api 如何使用 客戶端代碼 Document (function() { var sour...

    lixiang 評論0 收藏0
  • H5數(shù)據(jù)推送

    摘要:本文則試著和讀者一起對這個數(shù)據(jù)推送的需求進(jìn)行技術(shù)方案的探究。數(shù)據(jù)推送有兩種替代方案無更新方案和數(shù)據(jù)拉取方案。數(shù)據(jù)拉取和數(shù)據(jù)推送的功能目標(biāo)是一致的讓用戶看到最新的數(shù)據(jù)。但數(shù)據(jù)推送有一些優(yōu)勢,即更低的延遲。 前言 眾所周知,AJAX的出現(xiàn)是前端快速發(fā)展的一個標(biāo)志,同時也是前后端得以分離的重要基礎(chǔ)。作為一個C/S網(wǎng)絡(luò)的web系統(tǒng),網(wǎng)絡(luò)通信在發(fā)揮著舉足輕重的作用。大部分的場景下,我們是主動觸發(fā)...

    劉德剛 評論0 收藏0
  • H5數(shù)據(jù)推送

    摘要:本文則試著和讀者一起對這個數(shù)據(jù)推送的需求進(jìn)行技術(shù)方案的探究。數(shù)據(jù)推送有兩種替代方案無更新方案和數(shù)據(jù)拉取方案。數(shù)據(jù)拉取和數(shù)據(jù)推送的功能目標(biāo)是一致的讓用戶看到最新的數(shù)據(jù)。但數(shù)據(jù)推送有一些優(yōu)勢,即更低的延遲。 前言 眾所周知,AJAX的出現(xiàn)是前端快速發(fā)展的一個標(biāo)志,同時也是前后端得以分離的重要基礎(chǔ)。作為一個C/S網(wǎng)絡(luò)的web系統(tǒng),網(wǎng)絡(luò)通信在發(fā)揮著舉足輕重的作用。大部分的場景下,我們是主動觸發(fā)...

    nidaye 評論0 收藏0

發(fā)表評論

0條評論

sf190404

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<