初面网初面网

服务器发送事件(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)

  1. 先安装依赖:
npm init -y
npm install express cors
  1. 后端代码
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}`)
})

运行测试

  1. 先启动后端服务:
node server.js
  1. 启动前端 Vue 项目(确保 Vue 项目运行在 http://localhost:8080 端口)

  2. 点击页面上的“连接 SSE”按钮,即可建立连接并接收后端推送的消息。

更新于 2025/12/14