LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發文檔 其他文檔  
 
網站管理員

HTTP/2 + SSE 能否完全替代 Websocket嗎?

admin
2025年5月1日 11:47 本文熱度 58

1. 什么是 SSE(Server-Sent Events)

服務器發送事件 (SSE) 是一種標準化協議,允許 Web 服務器將數據推送到客戶端而無需使用替代機制,例如: ping、長輪詢 (Long Polling) 或 WebSocket。


服務器發送事件(SSE)是 HTML5 公布的一種服務器向瀏覽器客戶端發起數據傳輸的技術。一旦創建了初始連接,事件流將保持打開狀態 直到客戶端關閉。該技術通過傳統的 HTTP 發送,并具有 WebSocket 缺乏的各種功能,例如:自動重新連接、 事件 ID 以及 發送任意事件 的能力。

?? SSE 本身并沒有提供自動重連的機制,其所謂的自動重連特性是指 ` 瀏覽器自動處理與服務器的連接斷開并嘗試重新連接的過程 `。當然開發者也可以通過 `eventSource.retry = 5000` 手動重連。

SSE 就是利用服務器向客戶端聲明,接下來要發送的是流信息(streaming),會連續不斷地發送過來。這時,客戶端不會關閉連接,會一直等著服務器發過來的新的數據流,可以類比視頻流。SSE 就是利用這種機制,使用流信息向瀏覽器推送信息。其基于 HTTP 協議,目前除了 IE/Edge,其他瀏覽器都支持。

Content-Type: text/event-stream// 必須是 UTF-8 編碼的文本,流本質就是下載Cache-Control: no-cacheConnection: keep-alive

使用 SSE 可以 顯著節省便攜式設備的帶寬和電池壽命,并且可以與現有的基礎設施配合使用,因為其直接通過 HTTP 協議運行而無需像 WebSockets 那樣進行連接升級。

2.SSE 如何借力 HTTP2 補齊與 WebSocket 的短板

由于 SSE 是基于 HTTP 的,其天然適配于 HTTP/2,這樣 SSE 就可以集兩者之長:HTTP/2 可以基于多路復用流形成一個高效傳輸層,同時 SSE 給應用提供了 API 使之能夠進行推送 。

?? 流就是一個獨立的、在客戶端服務器之間的 HTTP/2 連接上雙向的幀序列,其最重要的一個特征就是 ` 單個 HTTP/2 連接可以包含多個并發開啟的流 `,其中每個端點都交錯著來自多個流的幀。



假如應用使用 HTTP/1 傳輸,此時 NetWork 選項卡可能會有如下的輸出:



瀏覽器會并行打開多個 HTTP/1.x 連接來加速頁面加載,而 不同的瀏覽器針對同一域名并發打開的連接數量有不同的限制,基本上都會支持 6 個左右不同的連接。

為了克服這個限制,類似于 域名分片的技術就被用來將資源分布在多個域名上。這些技術(可以將其認為是非法入侵)包括 JavaScript 和 CSS 文件、圖像和資源內聯,在 HTTP/2 世界中反而適得其反。這可能是遷移到 HTTP/2 時受到的最主要的影響了,即 消除多年以來所做的優化。

當使用 HTTP/2 的時候,NetWork 中會看到瀏覽器使用單個多路復用的連接,帶來更快的加載時間。



而 SSE 是基于 HTTP 的,這意味著使用 HTTP/2 的時候,不僅僅可以在一個 TCP 連接上交錯多個 SSE 流,同時還可以將多個 SSE 流(服務器到客戶端推送)與多個客戶端請求(客戶端到服務器)交錯。

const http2 = require('http2');const fs = require('fs');// 創建 HTTP/2 服務器const server = http2.createSecureServer({    key: fs.readFileSync('server-key.pem'),    cert: fs.readFileSync('server-cert.pem')});server.on('stream', (stream, headers) => {    const path = headers[':path'];    const method = headers[':method'];    if (path === '/events' && method === 'GET') {        // 設置響應頭        stream.respond({            'content-type': 'text/event-stream',            ':status': 200        });        // 發送一條歡迎消息        stream.write(`data: Welcome! Current time is ${new Date().toISOString()}\n\n`);        // 每 5 秒發送一條消息        const intervalId = setInterval(() => {            stream.write(`data: Current time is ${new Date().toISOString()}\n\n`);        }, 5000);        // 清理工作        stream.on('close', () => {            clearInterval(intervalId);        });    } elseif (path === '/send-data' && method === 'POST') {        // 客戶端通過 fetch('https://localhost:3000/send-data') 發送消息到服務端        let body = '';        stream.on('data', chunk => {            body += chunk.toString();        });        stream.on('end', () => {            console.log('Received data:', body);            stream.respond({':status': 200});            stream.end(JSON.stringify({ status: 'success', data: body}));        });    } else {        stream.respond({':status': 404});        stream.end();    }});// 監聽端口server.listen(3000, () => {    console.log('Server running at https://localhost:3000/');});
// 下面是瀏覽器連接 HTTP/2 的示例const eventSource = new EventSource('https://localhost:3000/events');// 監聽消息事件eventSource.onmessage = function(event) {    const messageDiv = document.getElementById('messages');    const newMessage = document.createElement('div');    newMessage.textContent = `New message: ${event.data}`;    messageDiv.appendChild(newMessage);};// 監聽連接打開事件eventSource.onopen = function(event) {    console.log('Connection opened');};// 監聽錯誤事件eventSource.onerror = function(event) {    if (eventSource.readyState === EventSource.CLOSED) {        console.log('Connection closed');    } else {        console.log('Error occurred, attempting to reconnect...');    }};// 發送 HTTP/2 請求document.getElementById('sendButton').addEventListener('click', () => {    fetch('https://localhost:3000/send-data', {        method: 'POST',        headers: {            'Content-Type': 'application/json'        },        body: JSON.stringify({message: 'Hello, server!'})    })    .then(response => response.json())    .then(data => {        console.log('Response:', data);    })    .catch(error => {        console.error('Error:', error);    });});

比如上面的 http2 代碼示例:

  • 獨立的請求和響應:由于 HTTP/2 支持多路復用,每個請求和響應都是獨立的流,因此客戶端可以同時通過一個流接收 SSE 消息而另一個流發送 POST 請求。
  • 雙向通信:HTTP/2 支持雙向通信,允許服務器和客戶端在任何時候發送和接收數據。這意味著客戶端可以在接收 SSE 消息的同時,通過另一個流發送數據到服務器。

有了 HTTP/2 和 SSE 就可以使用一個純 HTTP 雙向連接,加之使用簡單的 API 使應用代碼注冊多個服務器推送。

雙向能力的缺失一直是 SSE 對比 Websocket 時最主要的短板。有了 HTTP/2 就彌補了這個短板,從而為跳過 Websocket 并堅持使用基于 HTTP 的機制提供了可能。

3.HTTP/2 + SSE 能完全替代 Websocket 嗎?

答案是 No,主要是 Websocket 已經被大量應用,同時在某些特定應用場景下,其底層設計致力于雙向能力,擁有較少的負載的優勢就會體現出來。假設需要在雙端之間交互大吞吐量的消息,其中上下流動的消息量大致差不多(比如,需要保持所有玩家同步的大型多人在線游戲),這種場景下 Websocket 可能會是更好的選擇。

如果考慮像是展示 實時市場新聞、市場數據、聊天應用 等場景的時候,依賴 HTTP/2 + SSE 會提供高效的雙向通信通道并保有留在 HTTP 世界的大量優勢:

  • Websocket 由于是 將一個 HTTP 連接升級到一個完全不同的,與 HTTP 協議沒有任何關系的協議,所以當考慮將其與現有 Web 基礎設施做兼容的時候就比較難受了。
  • 擴展性和安全:Web 基礎設施組件(防火墻,入侵檢測、負載均衡)已經基于 HTTP 建立、維護和設置了,這是一個大型 / 關鍵應用在彈性、安全性和可擴展性等方面更加友好的環境。

因此 HTTP/2 + SSE 能否完全替代 Websocket 的結論是:

  • HTTP/2 并非 HTTP 的完整替代
  • 類似于 域名分片、資源內聯和圖片拼接 等入侵入式技術在 HTTP/2 世界中正好適得其反
  • HTTP/2 不是類似于 Websocket 或者 SSE 這樣的推送技術的替代品,HTTP/2 推送只能被瀏覽器處理而非應用
  • 將 HTTP/2 和 SSE 結合起來提供高效的基于 HTTP 的雙向通信

Websocket 技術可能會繼續使用,但是 SSE 和其 EventSource API 同 HTTP/2 的能力相結合可以在多數場景下達到同樣的效果,而且會更簡單。

參考資料

https://zhuanlan.zhihu.com/p/37365892

https://blog.csdn.net/cnweike/article/details/116056371

https://www.infoq.com/articles/websocket-and-http2-coexist/

https://stackoverflow.com/questions/48344634/why-do-we-need-sse-when-we-have-http2-bidirectional-streaming



閱讀原文:原文鏈接


該文章在 2025/5/6 12:43:08 編輯過
關鍵字查詢
相關文章
正在查詢...
點晴ERP是一款針對中小制造業的專業生產管理軟件系統,系統成熟度和易用性得到了國內大量中小企業的青睞。
點晴PMS碼頭管理系統主要針對港口碼頭集裝箱與散貨日常運作、調度、堆場、車隊、財務費用、相關報表等業務管理,結合碼頭的業務特點,圍繞調度、堆場作業而開發的。集技術的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業的高效ERP管理信息系統。
點晴WMS倉儲管理系統提供了貨物產品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質期管理,貨位管理,庫位管理,生產管理,WMS管理系統,標簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務都免費,不限功能、不限時間、不限用戶的免費OA協同辦公管理系統。
Copyright 2010-2025 ClickSun All Rights Reserved

黄频国产免费高清视频,久久不卡精品中文字幕一区,激情五月天AV电影在线观看,欧美国产韩国日本一区二区
真人AV片免费在线看 | 亚洲2020一区二区中文字幕 | 夜夜久久久精品不卡 | 午夜亚洲国产理论片中文 | 亚洲AV永久精品一区二区在线 | 日本在线日韩在线一区二区 |