天天看點

前端長連接配接及場景的實作方式

作者:Usernameundefined

前端長連接配接有很多使用場景,例如在進行大資料清單異步請求時,中間層和用戶端建立長連接配接,将先期到達的資料發送并顯示到用戶端,然後持續到任務完成,這樣能擷取更好的使用者體驗。

另外就是一些web im之類的場景也常常使用到長連接配接

本文介紹長連接配接的一些基本實作和優缺點,以供大家參考學習!

前端長連接配接及場景的實作方式

定義

長連接配接可以指 HTTP 持久連接配接 (persistent connection),也可以指基于 TCP / UDP / QUIC / WebSocket 等一個或多個協定建立後可以持續收發消息的資料通路。

實作方式

一、 短輪詢

1.1 定義

http端輪詢是伺服器收到請求不管是否有資料都直接響應 http 請求;

其實就是普通的輪詢。指在特定的的時間間隔(如每1秒),由浏覽器對伺服器發出HTTP request,然後由伺服器傳回最新的資料給用戶端的浏覽器。

1.2 應用場景

傳統的web通信模式。背景處理資料,需要一定時間,前端想要知道後端的處理結果,就要不定時的向後端送出請求以獲得最新情況。

1.3 優點

前後端程式編寫比較容易。

1.4 缺點

  • 請求中有大半是無用,難于維護,浪費帶寬和伺服器資源;
  • 響應的結果沒有順序(因為是異步請求,當發送的請求沒有傳回結果的時候,後面的請求又被發送。而此時如果後面的請求比前面的請 求要先傳回結果,那麼目前面的請求傳回結果資料時已經是過時無效的資料了)。

1.5 執行個體:适于小型應用。

1.6 前端實作:

var xhr = new XMLHttpRequest();
    setInterval(function(){
        xhr.open('GET','/user');
        xhr.onreadystatechange = function(){
 
        };
        xhr.send();
    },1000)
           

二、 長輪詢comet

2.1 定義

用戶端向伺服器發送Ajax請求,伺服器接到請求後hold住連接配接,直到有新消息才傳回響應資訊并關閉連接配接,用戶端處理完響應資訊後再向伺服器發送新的請求。

2.2 優點

在無消息的情況下不會頻繁的請求,耗費資源小。

2.3 缺點

  • 伺服器hold連接配接會消耗資源
  • 傳回資料順序無保證,難于管理維護。
  • 浏覽器端對統一伺服器同時 http 連接配接有最大限制, 最好同一使用者隻存在一個長輪詢;

2.4 執行個體:WebQQ、Hi網頁版、Facebook IM。

2.5 前端實作:

function ajax(){
        var xhr = new XMLHttpRequest();
        xhr.open('GET','/user');
        xhr.onreadystatechange = function(){
              ajax();
        };
        xhr.send();
    }
           

長輪訓和短輪訓

相同點:

  • 可以看出 http 長輪詢和 http 短輪詢的都會 hold 一段時間;

不同點

  • 間隔發生在服務端還是浏覽器端: http 長輪詢在服務端會 hold 一段時間, http 短輪詢在浏覽器端 “hold”一段時間;

三、 http 長連接配接SSE

目前 http 協定普遍使用的是 1.1 版本, 之前有個 1.0 版本,兩者之間的一個差別是 1.1 支援 http 長連接配接, 或者叫持久連接配接。

1.0 不支援 http 長連接配接, 每次一個 http請求響應後都關閉 tcp 連接配接, 下個 http 請求會重建立立 tcp 連接配接.

3.1定義

多個 http 請求共用一個 tcp 連接配接; 這樣可以減少多次臨近 http 請求導緻 tcp建立關閉所産生的時間消耗.

http 1.1 中在請求頭和相應頭中用 connection字段辨別是否是 http長連接配接, connection: keep-alive, 表明是 http 長連接配接; connection:closed, 表明伺服器關閉 tcp 連接配接

與 connection 對應的一個字段是 keep-live, http 響應頭中出現, 他的格式是 timeout=30,max=5, timeout 是兩次 http 請求保持的時間(s), , max 是這個 tcp 連接配接最多為幾個 http請求重用

3.2優點

消息即時到達,不發無用請求;管理起來也相對友善。

3.3 缺點

伺服器維護一個長連接配接會增加開銷。

3.4前端實作

msdn中關于使用伺服器發送事件的文檔:https://developer.mozilla.org/zh-CN/docs/Web/API/Server-sent_events/Using_server-sent_events

阮一峰關于SSE的介紹:https://www.ruanyifeng.com/blog/2017/05/server-sent_events.html

代碼示例

服務端:

'use strict';

const http = require('http');

http.createServer((req, res) => {

  // 伺服器聲明接下來發送的是事件流
  res.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache',
    'Connection': 'keep-alive',
    'Access-Control-Allow-Origin': '*',
  });

  // 發送消息
  setInterval(() => {
    res.write('event: slide\n'); // 事件類型
    res.write(`id: ${+new Date()}\n`); // 消息 ID
    res.write('data: 7\n'); // 消息資料
    res.write('retry: 10000\n'); // 重連時間
    res.write('\n\n'); // 消息結束
  }, 3000);

  // 發送注釋保持長連接配接
  setInterval(() => {
    res.write(': \n\n');
  }, 12000);
}).listen(2000);           

用戶端:

'use strict';

if (window.EventSource) {
  // 建立 EventSource 對象連接配接伺服器
  const source = new EventSource('http://localhost:2000');

  // 連接配接成功後會觸發 open 事件
  source.addEventListener('open', () => {
    console.log('Connected');
  }, false);

  // 伺服器發送資訊到用戶端時,如果沒有 event 字段,預設會觸發 message 事件
  source.addEventListener('message', e => {
    console.log(`data: ${e.data}`);
  }, false);

  // 自定義 EventHandler,在收到 event 字段為 slide 的消息時觸發
  source.addEventListener('slide', e => {
    console.log(`data: ${e.data}`); // => data: 7
  }, false);

  // 連接配接異常時會觸發 error 事件并自動重連
  source.addEventListener('error', e => {
    if (e.target.readyState === EventSource.CLOSED) {
      console.log('Disconnected');
    } else if (e.target.readyState === EventSource.CONNECTING) {
      console.log('Connecting...');
    }
  }, false);
} else {
  console.error('Your browser doesn\'t support SSE');
}           

四、 Web Socket

4.1定義

Websocket是基于HTTP協定的,在和服務端建立了連結後,服務端有資料有了變化後會主動推送給前端。

4.2優點

請求響應快,不浪費資源。(傳統的http請求,其并發能力都是依賴同時發起多個TCP連接配接通路伺服器實作的(是以并發數受限于浏覽器允許的并發連接配接數),而websocket則允許我們在一條ws連接配接上同時并發多個請求,即在A請求發出後A響應還未到達,就可以繼續發出B請求。由于TCP的慢啟動特性(新連接配接速度上來是需要時間的),以及連接配接本身的握手損耗,都使得websocket協定的這一特性有很大的效率提升;http協定的頭部太大,且每個請求攜帶的幾百上千位元組的頭部大部分是重複的,websocket則因為複用長連接配接而沒有這一問題。)

4.3缺點:

  • 主流浏覽器支援的Web Socket版本不一緻;
  • 服務端沒有标準的API。

4.4執行個體:實作即時通訊:如股票交易行情分析、聊天室、線上遊戲等,替代輪詢和長輪詢

4.5 解決:解決了http協定的兩個問題。

  • 1.服務端的被動性。http協定是隻有用戶端詢問之後才回複。解決了同步有延遲的問題
  • 2.解決了伺服器上消耗資源的問題

4.6 實作:

//需要先npm install ws
 
//伺服器端
var Server = require('ws').Server;
var wss = new Server({
    port:2000
});
wss.on('connection',function(ws){
    ws.on('message',function(data){
        ws.send('你好,用戶端,我是伺服器!');
        console.log(data);
    })
});
 
//node用戶端
 
var WebSocket = require('ws');
var socket = new WebSocket('ws://localhost:2000/');
socket.on('open',function(){
    socket.send('你好,伺服器,我是用戶端');
});
socket.on('message',function(event){
    console.log(event);
})
 
//html用戶端(注:浏覽器用戶端與node用戶端隻需要一種)
 
<script>
    var socket = new WebSocket('ws://localhost:2000/');
    socket.onopen = function(){
 
    };
    socket.onmessage = function(event){
        console.log(event.data)
    }
</script>

           

4.7 WebSocket四個事件操作

  • onmessage收到伺服器響應時執行
  • onerroe 出現異常時執行
  • onopen 建立起連接配接時執行
  • onclose 斷開連接配接時執行
前端長連接配接及場景的實作方式

繼續閱讀