記錄--你還在使用websocket實現實時消息推送嗎?

来源:https://www.cnblogs.com/smileZAZ/p/18019671
-Advertisement-
Play Games

這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 前言 在日常的開發中,我們經常能碰見服務端需要主動推送給客戶端數據的業務場景,比如數據大屏的實時數據,比如消息中心的未讀消息,比如聊天功能等等。 本文主要介紹SSE的使用場景和如何使用SSE。 服務端向客戶端推送數據的實現方案有哪幾種? ...


這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助

前言

在日常的開發中,我們經常能碰見服務端需要主動推送給客戶端數據的業務場景,比如數據大屏的實時數據,比如消息中心的未讀消息,比如聊天功能等等。

本文主要介紹SSE的使用場景和如何使用SSE。

服務端向客戶端推送數據的實現方案有哪幾種?

我們常規實現這些需求的方案有以下三種

  1. 輪詢
  2. websocket
  3. SSE

輪詢簡介

在很久很久以前,前端一般使用輪詢來進行服務端向客戶端進行消息的偽推送,為什麼說輪詢是偽推送?因為輪詢本質上還是通過客戶端向服務端發起一個單項傳輸的請求,服務端對這個請求做出響應而已。通過不斷的請求來實現服務端向客戶端推送數據的錯覺。並不是服務端主動向客戶端推送數據。顯然,輪詢一定是上述三個方法里最下策的決定。

輪詢的缺點:

  1. 首先輪詢需要不斷的發起請求,每一個請求都需要經過http建立連接的流程(比如三次握手,四次揮手),是沒有必要的消耗。
  2. 客戶端需要從頁面被打開的那一刻開始就一直處理請求。雖然每次輪詢的消耗不大,但是一直處理請求對於客戶端來說一定是不友好的。
  3. 瀏覽器請求併發是有限制的。比如Chrome 最大併發請求數目為 6,這個限制還有一個前提是針對同一功能變數名稱的,超過這一限制的後續請求將會被阻塞。而輪詢意味著會有一個請求長時間的占用併發名額
  4. 而如果輪詢時間較長,可能又沒有辦法非常及時的獲取數據

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對於各大瀏覽器的相容性↓

註意哦,上圖是SSE對於瀏覽器的相容不是對於服務端的相容。

websocket和SSE有什麼區別?

輪詢

對於當前電腦的發展來說,幾乎很少出現同時不支持websocket和sse的情況,所以輪詢是在極端情況下瀏覽器實在是不支持websocket和see的下策。

Websocket和SSE

我們一般的服務端和客戶端的通訊基本上使用這兩個方案。首先聲明:這兩個方案沒有絕對的好壞,只有在不同的業務場景下更好的選擇。

SSE的官方對於SSE和Websocket的評價是

  1. WebSocket是全雙工通道,可以雙向通信,功能更強;SSE是單向通道,只能伺服器向瀏覽器端發送。
  2. WebSocket是一個新的協議,需要伺服器端支持;SSE則是部署在HTTP協議之上的,現有的伺服器軟體都支持。
  3. SSE是一個輕量級協議,相對簡單;WebSocket是一種較重的協議,相對複雜。
  4. SSE預設支持斷線重連,WebSocket則需要額外部署。
  5. 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 //長鏈接標識

SSE:相關文檔,文檔入口文檔入口文檔入口文檔入口

顯然,如果直接看api介紹不論是看這裡還是看官網,大部分同學都是比較懵圈的狀態,那麼我們寫個demo來看一下?

demo請看下方

我更建議您先把Demo跑起來,然後在看看上面這個w3cschool的SSE文檔。兩個配合一起看,會更方便理解些。

如何實操一個SSE鏈接?Demo↓

這裡Demo前端使用的就是最基本的html靜態頁面連接,沒有使用任何框架。 後端選用語言是node,框架是Express。

理論上,把這兩段端代碼複製過去跑起來就直接可以用了。

  1. 第一步,建立一個index.html文件,然後複製前端代碼Demo到index.html文件中,打開文件
  2. 第二步,進入一個新的文件夾,建立一個index.js文件,然後將後端Demo代碼複製進去,然後在該文件夾下執行
npm init          //初始化npm       
npm i express     //下載node express框架
node index        //啟動服務

在這一層文件夾下執行命令。

完成以上操作就可以把項目跑起來了

前端代碼Demo

<!DOCTYPE html>
<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>

後端代碼Demo(node的express)

const express = require('express'); //引用框架
const app = express(); //創建服務
const port = 8088; //項目啟動埠

//設置跨域訪問
app.all("*", function(req, res, next) {
	//設置允許跨域的功能變數名稱,*代表允許任意功能變數名稱跨域
	res.header("Access-Control-Allow-Origin", '*');
	//允許的header類型
	res.header("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With");
	//跨域允許的請求方式 
	res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
	// 可以帶cookies
	res.header("Access-Control-Allow-Credentials", true);
	if (req.method == 'OPTIONS') {
		res.sendStatus(200);
	} else {
		next();
	}
})

app.get("/sse",(req,res) => {
    res.set({
        'Content-Type': 'text/event-stream', //設定數據類型
        'Cache-Control': 'no-cache',// 長鏈接拒絕緩存
        'Connection': 'keep-alive' //設置長鏈接
      });

      console.log("進入到長連接了")
      //持續返回數據
      setInterval(() => {
        console.log("正在持續返回數據中ing")
        const data = {
          message: `Current time is ${new Date().toLocaleTimeString()}`
        };
        res.write(`data: ${JSON.stringify(data)}\n\n`);
      }, 1000);  
})

//創建項目
app.listen(port, () => {
	console.log(`項目啟動成功-http://localhost:${port}`)
})

效果

本文轉載於:

https://juejin.cn/post/7325730345840066612

如果對您有所幫助,歡迎您點個關註,我會定時更新技術文檔,大家一起討論學習,一起進步。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 轉載至我的博客 https://www.infrastack.cn ,公眾號:架構成長指南 背景 隨著公司業務快速發展,對業務數據進行增長分析的需求越來越迫切,與此同時我們的業務數據量也在快速激增、每天的數據新增量大概在30w 左右,一年就會產生1 個億的數據,顯然基於傳統MySQL資料庫已經無法支 ...
  • 玩轉 CMS 目前接手的內容管理系統(CMS)基於 ant-design-vue-pro(簡稱模板項目或ant-vue-pro) 開發的,經過許多次迭代,形成了現在的模樣(簡稱本地項目)。 假如讓一名新手接手這個項目,他會遇到很多問題,比如 .env 的作用、開發時後端介面沒有寫好如何聯調、樣式使用 ...
  • 前言 從vue3開始vue引入了巨集,比如defineProps、defineEmits等。我們每天寫vue代碼時都會使用到這些巨集,但是你有沒有思考過vue中的巨集到底是什麼?為什麼這些巨集不需要手動從vue中import?為什麼只能在setup頂層中使用這些巨集? vue 文件如何渲染到瀏覽器上 要回答上 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 前言 從vue3開始vue引入了巨集,比如defineProps、defineEmits等。我們每天寫vue代碼時都會使用到這些巨集,但是你有沒有思考過vue中的巨集到底是什麼?為什麼這些巨集不需要手動從vue中import?為什麼只能在setu ...
  • 文檔編輯功能提供了一系列的操作頁面的能力,使用戶能夠控制文檔結構,並調整文檔的佈局和格式,確保文檔內容以合理有序的方式精準呈現。 ComPDFKit 文檔編輯的優勢 插入或刪除頁面: 向文檔插入或刪除頁面,以滿足特定的排版要求。 文檔結構調整: 調整頁面排列順序或旋轉方向,以滿足特定的顯示或列印需求 ...
  • Howdz Dashboard —— 一個基於 Vue3、Typescript、Vite 的完全自定義配置的瀏覽器起始頁,支持 Chrome 插件和 Edge 插件。 ...
  • 隨著 JavaScript 開發變得越來越廣泛,命名空間和依賴關係變得越來越難以處理。人們已經開發出不同的解決方案以模塊系統的形式來解決這個問題。 CommonJS(CJS) CommonJS 是一種同步載入模塊的規範,主要用於伺服器端的 Node.js 環境。 // 模塊導出 module.exp ...
  • 為什麼在js中需要添加addEventListener()? 1.What? addEventListener(監聽器) EventTarget.addEventListener()方法將指定的監聽器註冊到 EventTarget 上,當該對象觸髮指定的事件時,指定的回調函數就會被執行。事件目標可以 ...
一周排行
    -Advertisement-
    Play Games
  • 1、預覽地址:http://139.155.137.144:9012 2、qq群:801913255 一、前言 隨著網路的發展,企業對於信息系統數據的保密工作愈發重視,不同身份、角色對於數據的訪問許可權都應該大相徑庭。 列如 1、不同登錄人員對一個數據列表的可見度是不一樣的,如數據列、數據行、數據按鈕 ...
  • 前言 上一篇文章寫瞭如何使用RabbitMQ做個簡單的發送郵件項目,然後評論也是比較多,也是準備去學習一下如何確保RabbitMQ的消息可靠性,但是由於時間原因,先來說說設計模式中的簡單工廠模式吧! 在瞭解簡單工廠模式之前,我們要知道C#是一款面向對象的高級程式語言。它有3大特性,封裝、繼承、多態。 ...
  • Nodify學習 一:介紹與使用 - 可樂_加冰 - 博客園 (cnblogs.com) Nodify學習 二:添加節點 - 可樂_加冰 - 博客園 (cnblogs.com) 介紹 Nodify是一個WPF基於節點的編輯器控制項,其中包含一系列節點、連接和連接器組件,旨在簡化構建基於節點的工具的過程 ...
  • 創建一個webapi項目做測試使用。 創建新控制器,搭建一個基礎框架,包括獲取當天日期、wiki的請求地址等 創建一個Http請求幫助類以及方法,用於獲取指定URL的信息 使用http請求訪問指定url,先運行一下,看看返回的內容。內容如圖右邊所示,實際上是一個Json數據。我們主要解析 大事記 部 ...
  • 最近在不少自媒體上看到有關.NET與C#的資訊與評價,感覺大家對.NET與C#還是不太瞭解,尤其是對2016年6月發佈的跨平臺.NET Core 1.0,更是知之甚少。在考慮一番之後,還是決定寫點東西總結一下,也回顧一下.NET的發展歷史。 首先,你沒看錯,.NET是跨平臺的,可以在Windows、 ...
  • Nodify學習 一:介紹與使用 - 可樂_加冰 - 博客園 (cnblogs.com) Nodify學習 二:添加節點 - 可樂_加冰 - 博客園 (cnblogs.com) 添加節點(nodes) 通過上一篇我們已經創建好了編輯器實例現在我們為編輯器添加一個節點 添加model和viewmode ...
  • 前言 資料庫併發,數據審計和軟刪除一直是數據持久化方面的經典問題。早些時候,這些工作需要手寫複雜的SQL或者通過存儲過程和觸發器實現。手寫複雜SQL對軟體可維護性構成了相當大的挑戰,隨著SQL字數的變多,用到的嵌套和複雜語法增加,可讀性和可維護性的難度是幾何級暴漲。因此如何在實現功能的同時控制這些S ...
  • 類型檢查和轉換:當你需要檢查對象是否為特定類型,並且希望在同一時間內將其轉換為那個類型時,模式匹配提供了一種更簡潔的方式來完成這一任務,避免了使用傳統的as和is操作符後還需要進行額外的null檢查。 複雜條件邏輯:在處理複雜的條件邏輯時,特別是涉及到多個條件和類型的情況下,使用模式匹配可以使代碼更 ...
  • 在日常開發中,我們經常需要和文件打交道,特別是桌面開發,有時候就會需要載入大批量的文件,而且可能還會存在部分文件缺失的情況,那麼如何才能快速的判斷文件是否存在呢?如果處理不當的,且文件數量比較多的時候,可能會造成卡頓等情況,進而影響程式的使用體驗。今天就以一個簡單的小例子,簡述兩種不同的判斷文件是否... ...
  • 前言 資料庫併發,數據審計和軟刪除一直是數據持久化方面的經典問題。早些時候,這些工作需要手寫複雜的SQL或者通過存儲過程和觸發器實現。手寫複雜SQL對軟體可維護性構成了相當大的挑戰,隨著SQL字數的變多,用到的嵌套和複雜語法增加,可讀性和可維護性的難度是幾何級暴漲。因此如何在實現功能的同時控制這些S ...