前端 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 是一种 简单但不简单的技术,适合用在轻量推送、状态更新、进度条展示等场景。
不需要额外库,不需要双向握手,一行代码就能接收服务端实时推送!
如果你觉得这篇文章有帮助,别忘了点个 收藏 + 点赞 + 关注!