在日常的開發中,我們經常能碰見服務端需要主動推送給客戶端資料的業務場景,比如資料大屏的實時資料,比如訊息中心的未讀訊息,比如聊天功能等等。
服務端向客戶端推送資料的實現方案有哪幾種?
- 輪詢
- websocket
- SSE
輪詢簡介
在很久很久以前,前端一般使用輪詢來進行服務端向客戶端進行訊息的偽推送,為什麼說輪詢是偽推送?因為輪詢本質上還是透過客戶端向服務端發起一個單項傳輸的請求,服務端對這個請求做出響應而已。透過不斷的請求來實現服務端向客戶端推送資料的錯覺。並不是服務端主動向客戶端推送資料。顯然,輪詢一定是上述三個方法裡最下策的決定。
輪詢的缺點:
首先輪詢需要不斷的發起請求,每一個請求都需要經過http建立連線的流程(比如三次握手,四次揮手),是沒有必要的消耗。
客戶端需要從頁面被開啟的那一刻開始就一直處理請求。雖然每次輪詢的消耗不大,但是一直處理請求對於客戶端來說一定是不友好的。
瀏覽器請求併發是有限制的。比如Chrome 最大併發請求數目為 6,這個限制還有一個前提是針對同一域名的,超過這一限制的後續請求將會被阻塞。而輪詢意味著會有一個請求長時間的佔用併發名額。
而如果輪詢時間較長,可能又沒有辦法非常及時的獲取資料
websocket簡介
websocket是一個雙向通訊的協議,他的優點是,可以同時支援客戶端和服務端彼此相互進行通訊。功能上很強大。
缺點也很明顯,websocket是一個新的協議,ws/wss。也就是說,支援http協議的瀏覽器不一定支援ws協議。
相較於SSE來說,websocket因為功能更強大。結構更復雜。所以相對比較重。
websocket對於各大瀏覽器的相容性
SSE簡介
sse是一個單向通訊的協議也是一個長連結,它只能支援服務端主動向客戶端推送資料,但是無法讓客戶端向服務端推送訊息。
長連結是一種HTTP/1.1的持久連線技術,它允許客戶端和伺服器在一次TCP連線上進行多個HTTP請求和響應,而不必為每個請求/響應建立和斷開一個新的連線。長連線有助於減少伺服器的負載和提高效能。
SSE的優點
它是一個輕量級的協議,相對於websockte來說,他的複雜度就沒有那麼高,相對於客戶端的消耗也比較少。而且SSE使用的是http協議(websocket使用的是ws協議),也就是現有的服務端都支援SSE,無需像websocket一樣需要服務端提供額外的支援。
注意:IE大魔王不支援SSE
SSE對於各大瀏覽器的相容性
websocket和SSE有什麼區別?
輪詢
對於當前計算機的發展來說,幾乎很少出現同時不支援websocket和sse的情況,所以輪詢是在極端情況下瀏覽器實在是不支援websocket和see的下策。
Websocket和SSE
我們一般的服務端和客戶端的通訊基本上使用這兩個方案。首先宣告:這兩個方案沒有絕對的好壞,只有在不同的業務場景下更好的選擇。
SSE的官方對於SSE和Websocket的評價是
- WebSocket是全雙工通道,可以雙向通訊,功能更強;SSE是單向通道,只能伺服器向瀏覽器端傳送。
- WebSocket是一個新的協議,需要伺服器端支援;SSE則是部署在HTTP協議之上的,現有的伺服器軟體都支援。
- SSE是一個輕量級協議,相對簡單;WebSocket是一種較重的協議,相對複雜。
- SSE預設支援斷線重連,WebSocket則需要額外部署。
- SSE支援自定義傳送的資料型別。
Websocket和SSE分別適用於什麼業務場景?
對於SSE來說,它的優點就是輕,而且對於服務端的支援度要更好。換言之,可以使用SSE完成的功能需求,沒有必要使用更重更復雜的websocket。
比如:資料大屏的實時資料,訊息中心的訊息推送等一系列只需要服務端單方面推送而不需要客戶端同時進行反饋的需求,SSE就是不二之選。
對於Websocket來說,他的優點就是可以同時支援客戶端和服務端的雙向通訊。所適用的業務場景:最典型的就是聊天功能。這種服務端需要主動向客戶端推送資訊,並且客戶端也有向服務端推送訊息的需求時,Websocket就是更好的選擇。
SSE有哪些主要的API?
建立一個SSE連結 :var source = new EventSource(url);
SSE連線狀態
source.readyState
0,相當於常量EventSource.CONNECTING,表示連線還未建立,或者連線斷線。
1,相當於常量EventSource.OPEN,表示連線已經建立,可以接受資料。
2,相當於常量EventSource.CLOSED,表示連線已斷,且不會重連。
SSE相關事件
open事件(連線一旦建立,就會觸發open事件,可以定義相應的回撥函式)
message事件(收到資料就會觸發message事件)
error事件(如果發生通訊錯誤(比如連線中斷),就會觸發error事件)
資料格式
Content-Type: text/event-stream //文字返回格式
Cache-Control: no-cache //不要快取
Connection: keep-alive //長連結標識
前端程式碼 demo
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<ul id="ul">
</ul>
</body>
<script>
//生成li元素
function createLi(data){
let li = document.createElement("li");
li.innerHTML = String(data.message);
return li;
}
//判斷當前瀏覽器是否支援SSE
let source = ''
if (!!window.EventSource) {
source = new EventSource('http://localhost:8088/sse/');
}else{
throw new Error("當前瀏覽器不支援SSE")
}
//對於建立連結的監聽
source.onopen = function(event) {
console.log(source.readyState);
console.log("長連線開啟");
};
//對服務端訊息的監聽
source.onmessage = function(event) {
console.log(JSON.parse(event.data));
console.log("收到長連線資訊");
let li = createLi(JSON.parse(event.data));
document.getElementById("ul").appendChild(li)
};
//對斷開連結的監聽
source.onerror = function(event) {
console.log(source.readyState);
console.log("長連線中斷");
};
</script>
</html>