前端 SSE 實戰應用:用最簡單的方式實現實時推送
📌 點贊收藏關注不迷路!
在前端項目中,我們常聽到“實時通信”這個需求 —— 聊天、進度、狀態變化、系統消息。
但提到實時,大家首先想到的是 WebSocket,對吧?
其實還有一種更輕量、簡單、優雅的實時推送方案,那就是:
? SSE(Server-Sent Events)
本文將帶你深入理解并實戰實現一個前端 SSE 應用,包括:
- 什么是 SSE,它與 WebSocket、輪詢的區別
- 如何在 Vue / 原生項目中接入 SSE
- 封裝一個穩定的
useSSE
Hook - 前后端完整交互示例:推送進度條、系統消息
- 使用中斷、自動重連、心跳優化技巧
🌟 一、什么是 SSE?和 WebSocket 有什么區別?
SSE(Server-Sent Events) 是 HTML5 標準中的一種服務端推送技術,通過 EventSource
對象與服務端建立單向持久連接,服務器可以持續向客戶端推送事件數據。
特性 | SSE | WebSocket | 輪詢 |
---|---|---|---|
連接方向 | 單向(服務端 → 客戶端) | 雙向(全雙工) | 客戶端輪詢請求服務端 |
實現復雜度 | ? 很簡單 | 較復雜(需協議握手) | 簡單但浪費資源 |
兼容性 | Chrome / Firefox / Safari | 全面 | 全面 |
重連機制 | ? 內置自動重連 | ? 需手動實現 | 無連接 |
使用場景 | 狀態推送、日志、監控通知 | 聊天、游戲、協同編輯等 | 簡單數據刷新 |
🚀 二、前端如何使用 SSE?基礎示例
SSE 的核心是 EventSource
對象:
const source = new EventSource('/sse')source.onmessage = (event) => {console.log('收到消息:', event.data)
}source.onerror = (err) => {console.error('連接異常:', err)
}
📌 onmessage
是默認事件監聽,也可以監聽自定義事件:
source.addEventListener('progress', (e) => {console.log('任務進度:', e.data)
})
?? 三、SSE 服務端返回格式
服務端 SSE 響應格式必須是 text/event-stream
,并遵循以下格式:
event: progress
data: 任務已完成 40%
\n
關鍵點:
- 必須設置響應頭:
Content-Type: text/event-stream
- 每條消息以
\n\n
結束 - 支持
id: xxx
、retry: 5000
設置消息 ID 和重連時間
🔧 四、Vue 中封裝 useSSE Hook(支持斷開/重連)
// useSSE.ts
import { ref, onUnmounted } from 'vue'export function useSSE(url: string) {const data = ref<string | null>(null)const connected = ref(false)let source: EventSource | null = nullconst connect = () => {if (source) source.close()source = new EventSource(url)connected.value = truesource.onmessage = (event) => {data.value = event.data}source.onerror = () => {connected.value = falsesource?.close()// 自動嘗試重連由 EventSource 自帶實現}}const close = () => {source?.close()connected.value = false}onUnmounted(() => {close()})return {data,connected,connect,close,}
}
🧪 五、前后端實戰:實時推送任務進度條
? 后端示例(Node.js + Express)
// server.js
import express from 'express'
const app = express()app.get('/sse', (req, res) => {res.setHeader('Content-Type', 'text/event-stream')res.setHeader('Cache-Control', 'no-cache')res.setHeader('Connection', 'keep-alive')let progress = 0const timer = setInterval(() => {progress += 10res.write(`event: progress\ndata: ${progress}\n\n`)if (progress >= 100) clearInterval(timer)}, 1000)req.on('close', () => {console.log('客戶端斷開連接')clearInterval(timer)})
})app.listen(3000, () => {console.log('SSE 服務器已啟動: http://localhost:3000/sse')
})
? 前端頁面
<template><div><p>當前進度:{{ data }}</p><button @click="connect">開始監聽</button><button @click="close">斷開連接</button></div>
</template><script setup lang="ts">
import { useSSE } from './composables/useSSE'const { data, connect, close } = useSSE('http://localhost:3000/sse')
</script>
🛡 六、SSE 最佳實踐建議
? 建議:
- 為每條消息設置
event:
,區分不同事件類型 - 每條消息設置
id:
,支持客戶端斷線重連后定位 - 長連接可設置
retry:
,客戶端自動重連間隔 - 可加入心跳機制(如每 30 秒發一次 ping)
🔄 七、如果你想手動重連
雖然瀏覽器自帶 SSE 自動重連機制,但你也可以自己控制:
source.onerror = () => {console.log('斷線,5秒后重連')setTimeout(connect, 5000)
}
🧠 八、適合用 SSE 的場景有哪些?
場景 | 推薦使用 |
---|---|
后臺任務進度 | ? |
系統消息通知 | ? |
數據監控/實時日志 | ? |
聊天/游戲等雙向通信 | ?(建議 WebSocket) |
? 最后說一句
SSE 是一種 簡單但不簡單的技術,適合用在輕量推送、狀態更新、進度條展示等場景。
不需要額外庫,不需要雙向握手,一行代碼就能接收服務端實時推送!
如果你覺得這篇文章有幫助,別忘了點個 收藏 + 點贊 + 關注!