--- title: '【教學】🚀 SSE、WebSocket與Polling大PK!實時長連接通訊技術萌新指南 ✨!' disqus: hackmd --- # 【教學】🚀 SSE、WebSocket與Polling大PK!實時長連接通訊技術萌新指南 ✨! ![sse](https://hackmd.io/_uploads/H1nZSmEhxe.png) ## 🌟 摘要 嘿!想知道怎麼讓你的網站像聊天室一樣即時更新嗎?🤔 本篇文章要來解密三種實時通訊技術: * **Server-Sent Events (SSE)** * **WebSocket** * **Polling** 我們會用最白話的方式告訴你它們到底在幹嘛、什麼時候該用哪一個,還有維護起來會不會讓你想哭 😭😭😭 ## 💡 引言 現在的WEB APP都可能遇到要求「即時」更新的功能。 ⚡⚡新訊息要馬上彈出來、股價、幣種行情要即時跳動、聊天室訊息要秒出現!但是要怎麼選擇合適的技術來實現這些需求呢? 其實這大段時間,提起這種技術,很多人都會陷入困惑: - 「WebSocket 我知道有這東西,聽起來很厲害,但好像很複雜?」🤯 - 「Polling 實作很簡單,但會不會太耗資源?」😰 - 「SSE 是什麼?聽都沒聽過!」🙃 **好啦,開始劃重點!** 📝 很多人都誤會 SSE 和 WebSocket 一樣複雜,但其實 SSE 根本就省事太多了!它基於標準 HTTP,瀏覽器還內建重連功能! --- ## 🏆 學術界都說讚!權威研究報告出爐 在開始之前,先給大家看個超厲害的研究報告!📊 **瑞典布萊金理工學院** 的學者們做了一個超詳細的性能測試(沒錯,就是那種很嚴肅的學術研究 🤓),他們比較了這幾種技術的真實表現: 🔗 研究報告: [《Performance comparison of XHR polling, Long polling, Server sent events and Websockets》](https://www.diva-portal.org/smash/get/diva2:1133465/FULLTEXT01.pdf) - **TCP連接數據** (第26頁):XHR會導致連接數激增(高達289個連接),而其他技術保持在100個連接 - **研究結論** (第42-43頁) - **性能測試結果** (第24-37頁) ### 📈 驚人的發現: - **TCP連接大爆炸** 💥:傳統的XHR Polling 會產生高達 **289個連接**!而其他技術只需要100個左右 - **效能冠軍揭曉** 🥇:報告第43頁直接下結論: > 💬 "Websockets and Server sent events were measured to be the highest performing of the studied technologies." > 翻譯:WebSocket 和 SSE 就是本次比較雙冠王!🎉 ### 性能比較表 | 技術 | 延遲 | 頻寬使用 | CPU使用 | 服務器負載 | 成本與擴展性 | |------|------|----------|----------|------------|--------------| | **HTTP Polling** | 高(受輪詢間隔限制) | 最高(每次完整HTTP請求) | 中 | 高(大量TCP連接) | 差(高併發連接爆炸) | | **SSE** | 低(即時推送) | 低(僅傳輸新資料) | 低 | 中(單向長連接) | 佳(標準HTTP) | | **WebSocket** | 最低(全雙工) | 最低(最小幀開銷) | 低 | 中(需維護連接) | 中(需特殊配置) | ## 🔄 HTTP Polling:老派但實用的笨方法 ### 🤔 什麼是 Polling? 就是最簡單粗暴的方法啦!想像他是個很黏人的小小孩,每隔5秒就問媽媽「有新訊息嗎?有新訊息嗎?有新訊息嗎?」🥺 你的網頁就是那個小鬼,Server 就是覺得他很吵卻又一臉無奈的馬麻... 😅 ### ⚙️ 怎麼實作? 超級簡單!用我們熟悉的工具就行: - 拿出你的 `fetch()` 或 `Axios` 📞 - 設個定時器 `setInterval()` ⏰ - 每隔幾秒戳一下伺服器:「欸欸欸,有更新嗎?」 ### 🔍 底層到底發生了什麼? 每次問問題的時候: - 🤝 建立全新的 TCP 連線(握手) - 📤 送出完整的 HTTP 請求 - 📥 接收回應 - 👋 關閉連線(掰掰) - ⏱️ 等個幾秒...然後重複循環! ### 然後... 😰 問題來了... 如果你的瀏覽器有30個分頁同時開著,每個都在問「有更新嗎?」,伺服器就會: - **崩潰邊緣** 💥:連線數量爆炸增長 - **荷包大失血** 💸:每次後端都要處理完整的 HTTP 請求 這其實和💥**DDoS**💥是差不多的行為,拜託一定要慎用! 但如果你的資料更新頻率超低(比如每5~10分鐘才更新一次天氣),那 Polling 其實還OK啦~ 🌤️ --- ## 📡 SSE:簡單容易上手!建置成本最低的長連接! ### 💖 為什麼選 SSE? - **HTTP 就是王道** 👑:不需要特殊伺服器,現有的就能用 - **一條連線走天下** 🛣️:建立一次連線就能一直用 - **瀏覽器是暖男** 🥰:自動幫你處理重連,不用自己寫Message Queue - **最現代的解決方案** 🚀:使用HTML 5專門的 `EventSource` API,可穿透大多數代理和防火牆 ### 🛠️ 怎麼用 SSE? 瀏覽器內建就有: ```javascript // 就這麼簡單!🎉 const eventSource = new EventSource('/api/sse?token=your-token'); eventSource.onmessage = function(event) { console.log('收到新訊息啦!', event.data); // 在這裡更新你的 UI ✨ }; // 自動重連?瀏覽器幫你搞定!😎 ``` 不過要特別注意喔,根據瀏覽器相容支援表來看 目前比較新版本的 Android Chrome才有支援,iOS Safari則沒問題! ![image](https://hackmd.io/_uploads/B1Dm6M4nle.png) ### 🔧 實作細節大揭密 - **單向溝通** 📤:只有伺服器可以推送給你(但通常這就夠了) - **文字格式** 📝:傳輸純文字資料,通常是 JSON - **Token 問題** 🎫:Header 放不了 token,要用 query string 或 cookie - **自動重連** 🔄:斷線了?瀏覽器自動幫你重連! - **需心跳檢測** 💖:每秒後端最好都傳個ping訊息防止斷開! - **事件 ID** 🆔:有 `Last-Event-ID` 機制,重連後只拿新訊息 - **輕微延遲** ⏱️:走 HTTP chunked 傳輸,比 WebSocket 慢個1-100ms(但感覺不出來啦~) ### 🎯 最適合的場景 - **通知系統** 🔔:新訊息、系統警告(1-100ms 延遲完全不影響) - **即時儀表板** 📊:股價、監控數據(人眼根本感覺不出來,除非真的要精準) - **後台管理系統** 🖥️:各組運營資料更新(單向推送就夠了) - **直播數據** 📺:觀看人數、彈幕統計(不需要毫秒級準確) --- ## 🔌 WebSocket:雙向溝通霸權 ### 🚀 WebSocket 的超能力 - **全雙工通訊** ⚽:客戶端和伺服器都能隨時發消息 - **速度超快** ⚡:建立連線後,開銷超級小 - **支援二進位** 🔢:不只文字,圖片、檔案都能傳 - **協議升級** 🎭:從 HTTP 搖身變成 WebSocket ### 🛠️ 怎麼使用? ```javascript // 建立 WebSocket 連線 const ws = new WebSocket('wss://your-server.com/socket'); ws.onopen = function() { console.log('連線成功!可以開始聊天了 🎉'); ws.send('Hello Server! 👋'); }; ws.onmessage = function(event) { console.log('收到回覆:', event.data); }; ws.onclose = function() { console.log('連線斷了...要重連嗎? 😥'); // 原生的websocket這裡要自己寫重連邏輯... 😅 }; ``` ### 但是...麻煩事也不少 **伺服器要特殊設定** 🔧: - 需要支援 WebSocket 協議的伺服器 - 可能需要額外的服務或模組 - 負載均衡器也要特殊處理 **自己動手做** 🔨: - 重連邏輯要自己寫 - 心跳檢測要自己處理 - 連線狀態要自己管理 **但是!有個超級英雄拯救了一切!** ![image](https://hackmd.io/_uploads/rJbyJQV2lx.png) ### 🌟 Socket.IO 的魔法功能: - **自動重連** 🔄:斷線了?自動重連!不用你操心! - **心跳包** 💓:自動幫你維持連線活躍 - **降級處理** 🎭:WebSocket 不行?自動降級到 Long Polling! - **房間系統** 🏠:輕鬆實現群組聊天、分頻道推送 - **事件驅動** ⚡:用 `emit` 和 `on` 就能輕鬆溝通 - **跨平台** 🌍:瀏覽器、Node.js、手機 App 都支援 ### 💻 Socket.IO 使用範例: ```javascript // 客戶端 - 超級簡單! import io from 'socket.io-client'; const socket = io('http://localhost:3000'); // 發送訊息 socket.emit('chat message', 'Hello World! 👋'); // 接收訊息 socket.on('chat message', (msg) => { console.log('收到訊息:', msg); }); // 加入房間 socket.emit('join room', 'room1'); // 連線狀態處理(自動處理,但你也可以監聽) socket.on('connect', () => console.log('連線成功!🎉')); socket.on('disconnect', () => console.log('斷線了,但會自動重連 😌')); ``` ```javascript // 伺服器端 - Node.js const io = require('socket.io')(server); io.on('connection', (socket) => { console.log('用戶連線了!🎉'); // 處理聊天訊息 socket.on('chat message', (msg) => { // 廣播給所有人 io.emit('chat message', msg); // 或者只發給特定房間 // socket.to('room1').emit('chat message', msg); }); // 處理房間加入 socket.on('join room', (room) => { socket.join(room); socket.to(room).emit('user joined', 'OOO加入了聊天!'); }); }); ``` ### 🎯 為什麼 Socket.IO 這麼受歡迎? - **開發速度快** ⚡:複雜功能幾行代碼搞定,MVP能快速落地 - **穩定性強** 🛡️:自動處理各種邊緣情況 - **功能豐富** 🎁:房間、namespace、middleware都有 - **社群強大** 👥:文檔完整、範例超多 - **生產就緒** 🏭:大公司都在用,經過實戰考驗 所以說,雖然原生 WebSocket 有些麻煩,但有了 Socket.IO,WebSocket 開發變得超級愉快!🎊 :::info 但別忘了這套東西可是前後端都要同時使用哦! Java Spring Boot、Golang、Rust都有對應的版本可以使用! 而前端大多時候就只要選Latest就行啦~ ::: **網路環境挑剔** 🌐: - 有些代理或防火牆會擋 WebSocket - 企業網路環境可能有限制 ### 🎯 最適合的場景 - **即時通訊** 💬:Messenger、Discord(需要雙向+超低延遲) - **多人遊戲** 🎮:需要毫秒級反應的即時互動 - **協同編輯** ✏️:Google Docs、Figma(多人同步編輯) - **即時交易** 📈:高頻交易系統(每毫秒都是錢!) ## 技術選擇指南 ### 📊 實時通訊技術選擇決策樹 ``` Q1: 需要雙向通訊嗎?(客戶端是否需要頻繁向服務發送消息?) ├── ✅ 是 → Q2 └── ❌ 否 → Q3 Q2: 是否需要極低的延遲和大量消息交換? ├── ✅ 是 → 🔌 推薦使用 WebSocket └── ❌ 否 → Q3 Q3: 環境是否涉及多個分頁同時打開? ├── ✅ 是 → Q4 └── ❌ 否 → Q5 Q4: 是否關注資源效率和簡化的維護? ├── ✅ 是 → 📡+ 推薦使用 SSE + SharedWorker └── ❌ 否 → Q5 Q5: 是否需要即時更新?(秒級或分鐘級響應) ├── ✅ 是 → 📡 推薦使用 SSE └── ❌ 否 → 🔄 使用簡單的 Polling 即可 ``` ### 🔄 適合使用Polling的場景 - 數據更新頻率和粒度都極低(如每五分鐘至十分鐘以上才更新) - 簡單實踐優先於效能,但通常成本不一定是最低,特別是瀏覽器記憶體比較危險 - 不需要即時性 - 後端架構難以支持長連接 ### 📡 適合使用SSE的場景 - 服務到客戶端的單向通訊需求 - 需要即時通知或更新,且須採成本最低路線 - 希望利用標準HTTP基礎設施 - 不考慮手機版 (Safari iOS和火狐可用但Chrome不行) - **實務應用**:通知系統、實時數據儀表板、即時行情、天氣更新等 ### 🤝 適合使用WebSocket的場景 - 雙向通訊需求(客戶端頻繁發送消息) - 極低延遲要求 - 大量訊息交換 - 有考慮配置專門的WebSocket服務 - **實務應用**:聊天室、多人遊戲、協同編輯工具(Figma、社群共筆工具)等 --- ## 🎯 總結 在選擇實時通訊技術時,每種方案都有其適用場景: ### 🔄 HTTP Polling - **適用場景**:低頻更新、簡單實現優先 - **劣勢**:多分頁環境下連接數量激增(🔄×30) - **維護成本**:低複雜度,但高服務器負載 ### 📡 SSE (Server-Sent Events) - **適用場景**:單向通知、實時儀表板、風險警報 - **優勢**:標準HTTP協議、瀏覽器原生重連、低維護成本 - **最佳實踐**:📡+ SSE結合SharedWorker實現多分頁共享單一連接 ### 🔌 WebSocket - **適用場景**:聊天室、雙向頻繁通訊、協同編輯 - **優勢**:全雙工通訊、低延遲、二進制支持 - **劣勢**:需專門服務器、手動重連邏輯、防火牆穿透挑戰 **對於運營後台這類多分頁環境,📡+ SSE結合SharedWorker提供了明顯的優勢**: - ⬇️ **顯著減少服務器連接數**(從30降至1,減少97%) - 🔔 **提供更一致、更可控的通知體驗**(主分頁控制聲音) - 🚀 **避免多分頁環境中的資源競爭和重複工作** - ⚡ **保持近乎實時的推送能力,無需複雜的WebSocket維護** 對於大多數通知、風控警報和數據更新場景,特別是在多分頁環境下,📡 **SSE提供了更優的性能/維護比**。當然,如果需要客戶端到服務的頻繁通訊,有條件的話則🔌 **WebSocket仍然是更佳選擇**。 --- ## 參考來源 ### Server-Sent Events (SSE) - **MDN Web Docs - Server-Sent Events**:[Server-sent events - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) - **WHATWG 標準 - Server-Sent Events**:[HTML Standard](https://html.spec.whatwg.org/multipage/server-sent-events.html) - **MDN Web Docs - EventSource API**:[EventSource - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/EventSource) ### WebSocket - **MDN Web Docs - WebSocket API**:[The WebSocket API (WebSockets) - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) - **WHATWG 標準 - WebSocket**:[WebSockets Standard](https://websockets.spec.whatwg.org/) ### SharedWorker - **MDN Web Docs - SharedWorker**:[SharedWorker - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/SharedWorker) - **MDN Web Docs - 使用 Web Workers**:[Using Web Workers - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers) --- ###### tags: `VueJS` `Vue3` `websocket` `SSE` `polling` `SocketIO` `APP開發` `跨平台APP開發` `前端開發` `Web Development`