服务器发送事件(SSE)
什么是SSE
SSE(Server-Sent Events)是一种服务器向客户端推送实时数据的技术。它基于 HTTP 协议,允许服务器主动发送事件到客户端,而不需要客户端主动请求。
核心要点
- 后端必须返回
Content-Type: text/event-stream,否则前端无法识别为SSE - 数据格式:后端发送数据必须遵循data: 内容\n\n 格式(多行数据可拆分成多个data: 行)
- 前端EventSource: onopen 连接成功回调, onmessage 接收数据回调, onerror 连接错误回调
- 跨域处理:后端需配置CORS,允许前端地址跨域
- 资源清理:客户端断开时,后端需要清理定时器并关闭连接,避免内存泄漏
- SSE仅支持
GET 请求,且是单向通信(后端→前端),如果需要前端→后端通信,需配合 AJAX/WS - 浏览器对 SSE 连接数有上限(通常单域名 6 个),避免滥用
- 若需要更复杂的双向通信,可考虑 WebSocket,但 SSE 更简单(无需握手,仅需 HTTP 长连接)
前端Vue3核心代码(单文件组件)
<template>
<!-- 显示流式接收的内容 -->
<div class="sse-container">
<h3>SSE 流式传输示例</h3>
<p v-for="(msg, index) in messages" :key="index">{{ msg }}</p>
<button @click="connectSSE" :disabled="isConnected">连接 SSE</button>
<button @click="closeSSE" :disabled="!isConnected">关闭连接</button>
</div>
</template>
<script setup>
import { ref, onUnmounted } from 'vue'
// 存储接收的消息
const messages = ref([])
// 标记连接状态
const isConnected = ref(false)
// EventSource 实例(SSE 核心对象)
let eventSource = null
/**
* 建立 SSE 连接
*/
const connectSSE = () => {
// 1. 创建 EventSource 实例,连接后端 SSE 接口
eventSource = new EventSource('http://localhost:3000/sse')
// 2. 连接成功回调
eventSource.onopen = () => {
console.log('SSE 连接成功')
isConnected.value = true
messages.value.push('✅ 已建立 SSE 连接,等待接收数据...')
}
// 3. 接收后端推送的消息(核心)
eventSource.onmessage = (e) => {
console.log('收到后端数据:', e.data)
// 将接收的消息添加到页面
messages.value.push(`📩 ${e.data}`)
}
// 4. 连接错误回调
eventSource.onerror = (err) => {
console.error('SSE 连接错误:', err)
isConnected.value = false
messages.value.push('❌ SSE 连接异常')
// 自动重连(可选,根据需求配置)
eventSource.close()
}
}
/**
* 关闭 SSE 连接
*/
const closeSSE = () => {
if (eventSource) {
eventSource.close()
isConnected.value = false
messages.value.push('🔌 已关闭 SSE 连接')
console.log('SSE 连接关闭')
}
}
// 组件卸载时关闭连接(防止内存泄漏)
onUnmounted(() => {
closeSSE()
})
</script>
<style scoped>
.sse-container {
max-width: 600px;
margin: 20px auto;
padding: 20px;
border: 1px solid #eee;
border-radius: 8px;
}
button {
margin-right: 10px;
padding: 8px 16px;
cursor: pointer;
}
button:disabled {
cursor: not-allowed;
opacity: 0.6;
}
</style>
后端Node.js核心代码(Express)
- 先安装依赖:
npm init -y
npm install express cors
- 后端代码
const express = require('express')
const cors = require('cors')
const app = express()
// 解决跨域(前端 Vue 通常运行在 8080 端口,后端 3000 端口)
app.use(cors({
origin: 'http://localhost:8080', // 允许前端地址跨域
credentials: true
}))
/**
* SSE 核心接口:/sse
* 必须设置响应头为 text/event-stream,且禁用缓存
*/
app.get('/sse', (req, res) => {
// 1. 设置 SSE 响应头(关键)
res.setHeader('Content-Type', 'text/event-stream')
res.setHeader('Cache-Control', 'no-cache') // 禁用缓存
res.setHeader('Connection', 'keep-alive') // 长连接
res.flushHeaders() // 立即发送响应头
// 2. 模拟后端持续推送数据(每 1 秒推一次)
let count = 0
const interval = setInterval(() => {
count++
const data = `后端推送的第 ${count} 条消息(${new Date().toLocaleTimeString()})`
// 3. 按 SSE 格式发送数据(必须以 data: 开头,\n\n 结尾)
res.write(`data: ${JSON.stringify(data)}\n\n`)
// 模拟推送 10 条后停止
if (count >= 10) {
clearInterval(interval)
res.write(`data: 推送结束\n\n`)
res.end() // 关闭连接
}
}, 1000)
// 4. 客户端断开连接时清理资源
req.on('close', () => {
clearInterval(interval)
res.end()
console.log('客户端断开 SSE 连接')
})
})
// 启动后端服务
const PORT = 3000
app.listen(PORT, () => {
console.log(`后端 SSE 服务运行在 http://localhost:${PORT}`)
})
运行测试
- 先启动后端服务:
node server.js
-
启动前端 Vue 项目(确保 Vue 项目运行在 http://localhost:8080 端口)
-
点击页面上的“连接 SSE”按钮,即可建立连接并接收后端推送的消息。