消息推送的三種常見方式:輪詢、SSE、WebSocket

摘要:本文介紹消息推送的三種常見方式輪詢(定時請求,易增負擔)與長輪詢(阻塞請求至有數據 / 超時,減少請求)、SSE(HTTP 單向實時傳輸,純文本、自動重連)、WebSocket(全雙工通信,含客戶端 API 與 Java 服務端 Endpoint 實現)。

1. 消息推送常見方式

1.1 輪詢方式

輪詢

  • 工作機制:瀏覽器按照指定的時間間隔,不斷向服務器發送 HTTP 請求(如示例中的?GET/poll)。服務器收到請求后,會實時返回數據給瀏覽器。
  • 特點不管服務器有沒有新數據,瀏覽器都會定時發請求這種方式可能導致請求過于頻繁即便服務器無數據更新,也會產生大量請求,增加服務器和網絡的負擔,而且如果輪詢間隔設置不合理,還可能出現數據更新的延遲(如圖中 “延遲” 所示)。

長輪詢

  • 工作機制:瀏覽器發送 Ajax 請求(如示例中的?GET/lpoll)后,服務器接收到請求會 “阻塞” 該請求。也就是說,服務器不會立即返回響應,而是等待有數據更新或者請求超時的時候,才會把數據返回給瀏覽器。
  • 特點:相比輪詢,長輪詢減少了不必要的請求次數。只有當有數據變化或者超時,服務器才會響應,能在一定程度上降低服務器和網絡的壓力,也能更及時地獲取數據更新(只要數據更新在超時前發生)。

簡單來說,輪詢是 “定時問”,長輪詢是 “問了等,有了才回”,二者在請求頻率、資源消耗和數據實時性等方面存在差異,可根據實際場景選擇使用。


1.2 SSE 技術

服務器發送事件(Server-Sent Events)是一種用于從服務器到客戶端的 單向、實時 數據傳輸技術,基于 HTTP協議實現。

    它有幾個重要的特點:

    1. 單向通信:SSE 只支持服務器向客戶端的單向通信,客戶端不能向服務器發送數據。
    2. 文本格式:SSE 使用?純文本格式?傳輸數據,使用 HTTP 響應的?text/event-stream?MIME 類型。(數據流信息)
    3. 保持連接:SSE 通過保持一個持久的 HTTP 連接,實現服務器向客戶端推送更新,而不需要客戶端頻繁輪詢。
    4. 自動重連:如果連接中斷,瀏覽器會自動嘗試重新連接,確保數據流的連續性。

    SSE 數據格式

    SSE 數據流的格式非常簡單,使用?event?指定事件名稱,用于區分不同類型的消息。每個事件使用 data 字段,作為消息主體,事件以兩個換行符結束。還可以使用 id 字段來標識事件,并且 retry 字段可以設置重新連接的時間間隔。

    event: 事件名\n    // 可選,用于區分不同類型的消息
    data: 消息內容\n    // 必選,消息主體(可多行,每行以 data: 開頭)
    id: 消息ID\n       // 可選,用于客戶端記錄最后接收的消息ID(重連時可通過 Last-Event-ID 頭傳遞)
    retry: 重連時間(毫秒)\n  // 可選,指定客戶端重連間隔
    \n  // 空行表示一條消息結束

    示例格式如下:

    data: Third message\n
    id: 3\n
    \n
    retry: 10000\n
    data: Fourth message\n
    \n

    1.3 WebSocket

    WebSocket 是一種網絡通信協議,它通過在單個、長期的連接上提供全雙工(雙向)的通信通道,來解決 HTTP 協議在實時通信方面的不足。

    1.3.1 原理解析

    這張圖解析了 WebSocket 連接的建立過程及原理,可分為以下幾個部分:

    連接建立階段(基于 HTTP 協議升級)

    1. 客戶端請求:客戶端向服務器發送一個特殊的 HTTP 請求,請求中包含?Upgrade: websocket?等頭信息,表明希望將連接從 HTTP 協議升級為 WebSocket 協議。下方 “請求數據” 框里展示了具體的請求內容,像?GET ws://localhost/chat HTTP/1.1(指定 WebSocket 連接的地址)、Connection: Upgrade(表示要升級連接)、Upgrade: websocket(明確升級到 WebSocket 協議)等。
    2. 服務器響應:服務器收到請求后,返回?HTTP/1.1 101 Switching Protocols?響應,確認協議升級。下方 “響應數據” 框里呈現了響應的具體內容,包含?Upgrade: websocketConnection: Upgrade?等,表明已切換到 WebSocket 協議。

    數據傳輸階段(基于 WebSocket 協議)

    當協議升級完成后,客戶端和服務器就可以基于 WebSocket 協議進行全雙工通信了,雙方能相互主動發送數據(圖中 “發送數據” 的雙向箭頭體現了這一點),不再受 HTTP 協議請求 - 響應模式的限制,適合實時性要求高的場景,比如在線聊天、實時數據推送等。

    1.3.2 客戶端API


    1. WebSocket 對象創建

    代碼示例:let ws = new WebSocket(URL);

    作用:在瀏覽器中創建一個 WebSocket 實例,用于和服務器建立 WebSocket 連接。

    URL 說明:

    • 格式為?協議://ip地址/訪問路徑
    • 其中協議名稱為?ws(若為加密連接則用?wss,類似 HTTPS),ip地址?是服務器的地址,訪問路徑?是 WebSocket 服務在服務器上的具體路徑。

    2. WebSocket 對象相關事件

    這部分通過表格列出了 WebSocket 實例常用的事件及對應的事件處理程序和描述:

    事件事件處理程序描述
    openws.onopen當客戶端與服務器成功建立 WebSocket 連接時觸發該事件。
    messagews.onmessage當客戶端接收到服務器發送的數據時觸發該事件。
    closews.onclose當 WebSocket 連接關閉時(無論是客戶端主動關閉,還是服務器關閉,或者連接異常斷開)觸發該事件。

    3. WebSocket 對象提供的方法

    這部分介紹了 WebSocket 實例的方法:

    方法名稱描述
    send()客戶端通過調用 WebSocket 實例的?send()?方法,向服務器發送數據。

    1.3.3 代碼實現
    <script>let ws = new WebSocket("ws://localhost/chat");ws.onopen = function() {};ws.onmessage = function(evt) {// 通過 evt.data 可以獲取服務器發送的數據};ws.onclose = function() {};
    </script>

    1. 創建 WebSocket 實例

    let ws = new WebSocket("ws://localhost/chat");
    
    • 使用?new WebSocket()?構造函數創建一個 WebSocket 連接對象。
    • 參數?"ws://localhost/chat"?是 WebSocket 服務器的地址,ws://?表示使用 WebSocket 協議(如果是加密的 WebSocket 連接,使用?wss://),localhost?是本地服務器地址,/chat?是具體的 WebSocket 端點路徑,用于標識要連接的服務。

    2. 處理連接建立事件(onopen

    ws.onopen = function() {// 連接成功建立后執行的代碼
    };
    
    • onopen?是 WebSocket 對象的一個事件處理屬性。
    • 當客戶端與 WebSocket 服務器成功建立連接時,這個函數會被調用。通常可以在這里執行一些連接成功后的操作,比如向服務器發送初始化消息等。

    3. 處理消息接收事件(onmessage

    ws.onmessage = function(evt) {// 通過 evt.data 可以獲取服務器發送的數據
    };
    
    • onmessage?事件在客戶端接收到服務器發送的數據時觸發。
    • 回調函數的參數?evt?包含了服務器發送的數據,通過?evt.data?可以獲取到具體的數據內容,數據可以是字符串、Blob 或者 ArrayBuffer 等格式,這里通常需要根據實際情況對數據進行解析和處理,比如展示聊天消息、更新實時數據等。

    4. 處理連接關閉事件(onclose

    ws.onclose = function() {// 連接關閉后執行的代碼
    };
    

    • onclose?事件在 WebSocket 連接關閉時觸發,不管是客戶端主動關閉還是服務器關閉連接,或者連接異常斷開,這個函數都會被調用。可以在這里進行一些資源清理、提示用戶連接已關閉或者嘗試重新連接等操作。

    1.3.4 服務端API

    Java WebSocket 應用由一系列的?Endpoint?組成。Endpoint?是一個 Java 對象,代表 WebSocket 鏈接的一端,對于服務端,我們可以視為處理具體 WebSocket 消息的接口。

    Endpoint 的定義方式

    我們可以通過兩種方式定義?Endpoint

    • 第一種是編程式,即繼承類?javax.websocket.Endpoint?并實現其方法。
    • 第二種是注解式,即定義一個 POJO,并添加?@ServerEndpoint?相關注解。

    Endpoint 的生命周期

    Endpoint?實例在 WebSocket 握手時創建,并在客戶端與服務端鏈接過程中有效,最后在鏈接關閉時結束。在?Endpoint?接口中明確定義了與其生命周期相關的方法,規范實現者確保生命周期的各個階段調用實例的相關方法。生命周期方法如下:

    方法描述注解
    onOpen()當開啟一個新的會話時調用,該方法是客戶端與服務端握手成功后調用的方法@OnOpen
    onClose()當會話關閉時調用@OnClose
    onError()當連接過程異常時調用@OnError

    1.3.5 服務端接收和推送數據

    1.3.6 代碼實現

    @ServerEndpoint("/chat")
    @Component
    public class ChatEndpoint {@OnOpen//連接建立時被調用public void onOpen(Session session, EndpointConfig config) {}@OnMessage//接收到客戶端發送的數據時被調用public void onMessage(String message) {}@OnClose//連接關閉時被調用public void onClose(Session session) {}
    }

    大功告成!

    本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
    如若轉載,請注明出處:http://www.pswp.cn/news/921890.shtml
    繁體地址,請注明出處:http://hk.pswp.cn/news/921890.shtml
    英文地址,請注明出處:http://en.pswp.cn/news/921890.shtml

    如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

    相關文章

    論文閱讀:ACL 2024 Stealthy Attack on Large Language Model based Recommendation

    總目錄 大模型相關研究&#xff1a;https://blog.csdn.net/WhiffeYF/article/details/142132328 https://arxiv.org/pdf/2402.14836 https://www.doubao.com/chat/19815566713551106 文章目錄速覽攻擊方法速覽一、攻擊核心目標與前提1. 核心目標2. 攻擊前提二、模型無關的簡單…

    自動駕駛中的傳感器技術43——Radar(4)

    本文對目前毫米波雷達中的天線設計進行比較全面的羅列&#xff0c;并進行簡單的設計評述 1、實際設計案例 圖1 涵蓋能寬窄覆蓋的天線設計&#xff08;無俯仰分辨率&#xff09;圖2 Bosch前雷達的天線設計&#xff08;有俯仰的分辨率但比較弱&#xff0c;也涵蓋了擴展覆蓋&…

    使用反轉法線材質球,實現切換天空盒相同的功能,優點:包體變小

    切換天空盒第一步先把SKY 天空球資源導入到工程里&#xff0c; 第二步&#xff1a;天空球文件下的SKY預制件拖入到場景里 第三步 選著SKY材質球&#xff0c;拖入自己的全景圖片(圖片分辨率不能超過5000*5000&#xff0c;否則手機無法顯示) 如果并沒有效果&#xff0c;看看圖…

    真正有效的數據指標體系應該長什么樣?

    真正有效的數據指標體系應該長什么樣&#xff1f;為什么大多數企業的指標體系都是"花架子"&#xff1f;真正有效的指標體系應該長什么樣&#xff1f;從數據到洞察&#xff1a;讓指標真正"活"起來結語在這個人人都在談數字化轉型的時代&#xff0c;企業就像…

    分布式專題——6 Redis緩存設計與性能優化

    1 多級緩存架構2 緩存設計 2.1 緩存穿透 2.1.1 簡介緩存穿透是什么&#xff1f;當查詢一個根本不存在的數據時&#xff0c;緩存層和存儲層都不會命中。正常邏輯下&#xff0c;存儲層查不到數據就不會寫入緩存層。這會導致&#xff1a;每次請求這個不存在的數據&#xff0c;都要…

    一文了解大模型壓縮與部署

    一文了解大模型壓縮與部署&#xff1a;從 INT4 量化到 MoE&#xff0c;讓大模型跑在手機、邊緣設備和云端&#x1f3af; 為什么需要模型壓縮與部署&#xff1f;你訓練了一個強大的大模型&#xff08;如 Qwen-72B、LLaMA-3-70B&#xff09;&#xff0c;但在部署時發現&#xff1…

    新手向:中文語言識別的進化之路

    自然語言處理&#xff08;NLP&#xff09;技術正在以前所未有的速度改變我們與機器的交互方式。根據Gartner最新報告顯示&#xff0c;全球NLP市場規模預計在2025年將達到430億美元&#xff0c;年復合增長率高達21%。而中文作為世界上使用人數最多的語言&#xff08;全球約15億使…

    LeetCode100-206反轉鏈表

    本文基于各個大佬的文章上點關注下點贊&#xff0c;明天一定更燦爛&#xff01;前言Python基礎好像會了又好像沒會&#xff0c;所有我直接開始刷leetcode一邊抄樣例代碼一邊學習吧。本系列文章用來記錄學習中的思考&#xff0c;寫給自己看的&#xff0c;也歡迎大家在評論區指導…

    uniapp開源多商戶小程序商城平臺源碼 支持二次開發+永久免費升級

    在電商行業競爭日益激烈的今天&#xff0c;擁有一個功能強大、靈活可拓展的多商戶小程序商城至關重要。今天給大家分享一款 uniapp 開源多商戶小程序商城平臺源碼&#xff0c;它不僅具備豐富的基礎功能&#xff0c;還支持二次開發&#xff0c;更能享受永久免費升級服務&#xf…

    使用腳本一鍵更新NTP服務器地址為自定義地址

    【使用場景】 在銀河麒麟桌面操作系統V10SP1-2303版本中使用腳本一鍵修改NTP服務器地址為自定義地址。 【操作步驟】 步驟1. 編寫shell腳本 ```bash desktop2303@desktop2303-pc:~$ vim setntptimeserver.sh #!/bin/bashfunction modifykylinconf() { # 檢查是否已存在目標配置…

    linux內核 - 內核架構概覽

    當 Linux 系統啟動時,內核會在啟動過程的早期階段接管控制——緊跟在固件(BIOS 或 UEFI)和引導加載程序完成任務之后。此時,壓縮的 Linux 內核鏡像會被加載到內存中,通常會附帶一個稱為 initramfs 的最小臨時根文件系統,它用于在切換到真實根文件系統并繼續系統初始化之前…

    [react] react-router-dom是啥?

    頁面路由&#xff0c;注意頁面路由不是路由器&#xff0c;因為我之前總是把路由和路由器搞混。而且我總是把前端頁面的路由和路由器的路由搞混。那么這里一定要明白&#xff0c;這里我所說的頁面路由就是指在瀏覽器里面的導航路由。 npm create vitelatest my-react-app – --t…

    HTTP簡易客戶端實現

    &#x1f310; HTTP簡易客戶端實現 流程圖&#xff1a; 引用&#xff1a; chnroutes2.cpp#L474 chnroutes2_getiplist() chnroutes2.cpp#L443 http_easy_get(…) &#x1f552; 1. 超時管理機制 (http_easy_timeout) &#x1f539; 核心功能&#xff1a;創建定時器自動關…

    建筑面LAS點云高度計算工具

    效果 例如中位數,計算后,在shp建筑面中添加一個字段meidian_hei 準備數據 1、建筑矢量面.shp 2、點云.las 界面 腳本 import laspy import shapefile # pyshp庫,處理POLYGONZ坐標格式異常 import pandas as pd import numpy as np import os import traceback # 打印…

    java day18

    繼續學習&#xff0c;學習sringboot案例&#xff1b;熟悉的三件套&#xff1b;比如做一個表&#xff0c;前端搭建好框架&#xff0c;然后返回給后端一個請求&#xff0c;說要這個表的數據吧&#xff1b;然后通過請求和規定的格式返回給后端之后&#xff0c;我們后端進行接收處理…

    并發編程原理與實戰(二十八)深入無鎖并發演進,AtomicInteger核心API詳解與典型場景舉例

    無鎖并發演進背景 隨著系統高并發的壓力越來越大&#xff0c;傳統同步機制在高并發場景下的性能瓶頸和缺點可能會逐漸顯露&#xff1a; &#xff08;1&#xff09;性能損耗&#xff1a;synchronized等鎖機制會導致線程阻塞和上下文切換&#xff0c;在高并發場景下性能損耗顯著。…

    整體設計 之 緒 思維導圖引擎 之 引 認知系統 之 引 認知系統 之 序 認知元架構 之5 : Class 的uml profile(豆包助手 之7)

    摘要&#xff08;AI生成&#xff09;三層中間件架構的約束邏輯體系1. 架構定位與功能分工三個中間層&#xff08;隔離層/隱藏層/防腐層&#xff09;構成數據處理管道&#xff0c;分別承擔&#xff1a;隔離層&#xff1a;跨系統數據轉換處理對象&#xff1a;異構數據&#xff08…

    iframe引入界面有el-date-picker日期框,點擊出現閃退問題處理

    前言&#xff1a;iframe引入界面有el-date-picker日期框&#xff0c;點擊出現閃退問題處理。問題情況&#xff1a;點擊開始日期的輸入部分&#xff0c;會出現閃退情況&#xff0c;該組件是iframe調用的內容問題分析&#xff1a;事件冒泡&#xff0c;點擊與聚焦的時候&#xff0…

    docker 拉取本地鏡像

    要在Docker中拉取本地鏡像&#xff0c;通常有以下幾種實現方法&#xff1a; 使用docker pull命令&#xff1a;可以使用docker pull命令從本地鏡像倉庫拉取鏡像。例如&#xff0c;如果本地鏡像的名稱是my-image&#xff0c;則可以運行以下命令拉取鏡像&#xff1a; docker pull …

    嘉立創EDA從原理圖框選住器件進行PCB布局

    1、先選中需要布局的模塊的相關器件2、設計-》布局傳遞3、在PCB會選中模塊相關的元器件&#xff0c;拖動進行布局4、依次將每個模塊都分類出來5、板框設計&#xff1a;如果有要求大小&#xff0c;可以先將單位設置為mm&#xff0c;然后畫出來板框的尺寸