当前位置: 首页 > news >正文

深入理解 SSE:服务器发送事件及其在前后端中的实践

前言

放假前接到一个需求,关于前端从服务器获取实时数据,之前用的是定时器,由于原因,诸多原因,产品拉会讨论新的方案,最后改成用SSE技术实现同样效果。

在此之前我对SSE等知识了解得比较少,因此在实践过程中写成一篇博客,和大家一起交流学习。

在实时 Web 应用开发中,我们经常需要从服务器获取实时数据。传统的轮询方式效率低下,而 WebSocket 虽然功能强大但实现复杂。

介绍一种轻量级的实时服务器推送技术 ——SSE(Server-Sent Events),以及如何在 Express 后端和 Vue2 前端中实现它。

一、什么是 SSE?

SSE(Server-Sent Events,服务器发送事件)是一种基于 HTTP 协议的技术,允许服务器主动向客户端持续推送数据。它的工作方式很简单:

  • 客户端发起一次 HTTP 请求建立连接
  • 服务器保持这个连接不关闭,有新数据时主动推送给客户端
  • 数据以简单的文本格式传输,每次推送都遵循特定格式
  • 当连接意外断开时,客户端会自动尝试重连

SSE 就像服务器给客户端开了一个专属推送通道,服务器可以随时向这个通道发送消息,而不需要客户端反复请求。

二、SSE 与 WebSocket 的区别

SSE 和 WebSocke都能实现服务器向客户端推送数据,但适用场景不同:

特性SSEWebSocket
通信方式单向(服务器→客户端)双向(全双工)
协议基于 HTTP独立的 WebSocket 协议
实现复杂度简单(浏览器原生支持)较复杂
重连机制自带自动重连需要手动实现
数据格式文本(简单格式)二进制或文本
适用场景通知、实时数据展示聊天、游戏等双向交互

简单来说,如果你只需要服务器向客户端(单向通信)推送数据(如实时监控面板、新闻推送),SSE 是更轻量的选择;如果需要双向通信(如即时聊天),则应该选择 WebSocket。

三、基础使用:前端如何使用 SSE?

现代浏览器(除 IE 外)原生支持 SSE,通过EventSource API 即可轻松使用:

// 建立连接
const source = new EventSource('/api/sse-endpoint');// 监听消息事件
source.onmessage = (event) => {console.log('收到数据:', event.data);// 处理数据...
};// 监听连接打开
source.onopen = () => {console.log('连接已建立');
};// 监听错误
source.onerror = (error) => {console.error('发生错误:', error);
};// 关闭连接(必要时)
// source.close();

SSE 还支持自定义事件类型,让我们可以更灵活地处理不同类型的消息:

// 监听自定义事件
source.addEventListener('temperatureUpdate', (event) => {console.log('温度更新:', event.data);
});source.addEventListener('systemMessage', (event) => {console.log('系统消息:', event.data);
});

四、实战演练

1、Express 后端实现 SSE

ps:如何创建express应用程序在本篇文章不会提及,有需要请阅读文章:

https://blog.csdn.net/orbit4/article/details/144678842

讲解如何在 Express 中实现 SSE 服务,主要分为以下几个步骤:

1. 设置正确的响应头

SSE 需要特定的 HTTP 头来告知客户端这是一个事件流:

res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
2. 保持连接并发送数据

与普通 HTTP 请求不同,SSE 连接需要保持打开状态。我们使用res.write()而不是res.send()res.end()来发送数据:

// 存储所有客户端连接
let clients = [];router.get('/', (req, res) => {// 设置SSE响应头res.setHeader('Content-Type', 'text/event-stream');res.setHeader('Cache-Control', 'no-cache');res.setHeader('Connection', 'keep-alive');res.flushHeaders();// 将新客户端添加到列表clients.push(res);// 发送连接确认res.write(`event: connected\n`);res.write(`data: ${JSON.stringify({ message: '已建立SSE连接' })}\n\n`);// 处理客户端断开req.on('close', () => {clients = clients.filter(client => client !== res);});
});
3. 遵循 SSE 数据格式

服务器发送的每条消息必须遵循特定格式:

  • data:开头,后跟实际内容
  • 每条消息以两个换行符 (\n\n) 结束
  • 可选指定event:字段来定义事件类型
  • 可选指定id:字段来标识消息
  • 可选指定retry:字段来建议重连间隔
// 定期向所有客户端发送数据
setInterval(() => {const data = {timestamp: new Date().toISOString(),temperature: (20 + Math.random() * 10).toFixed(2),humidity: (40 + Math.random() * 30).toFixed(2)};// 向每个连接的客户端发送数据clients.forEach(client => {client.write(`data: ${JSON.stringify(data)}\n\n`);});
}, 2000);
4. 处理跨域问题

由于我们的前端和后端可能运行在不同端口,需要配置 CORS:

//安装

npm install cors

const cors = require('cors');// 配置CORS允许所有来源
app.use(cors({origin: "*",methods: ["GET", "POST"],allowedHeaders: ["Content-Type"]
}));

2、Vue2 前端实现 SSE 客户端

在 Vue2 中使用 SSE,我们可以创建一个专门的组件来管理连接和处理数据:

1. 连接管理

在组件中,我们可以通过按钮控制 SSE 连接的建立和关闭:

methods: {toggleConnection() {if (this.isConnected) {this.disconnect();} else {this.connect();}},connect() {// 连接到后端SSE服务this.eventSource = new EventSource('http://localhost:3000/sse');// 监听消息事件this.eventSource.onmessage = (event) => {try {const data = JSON.parse(event.data);this.addMessage(data, false);this.startTypingEffect(this.messages.length - 1);} catch (error) {console.error('解析SSE数据失败:', error);}};// 监听连接打开和错误事件...},disconnect() {if (this.eventSource) {this.eventSource.close();this.eventSource = null;this.isConnected = false;}}
}
2. 实现打印机效果

为了让新消息以打字机效果展示,我们可以逐字显示文本并添加光标闪烁动画:

startTypingEffect(messageIndex) {const message = this.messages[messageIndex];if (message.isSystem) return;// 为每个字段启动打字效果Object.keys(message.content).forEach((field, fieldIndex) => {const text = message.content[field];const elementSelector = `.message-item:nth-child(${messageIndex + 1}) .data-field:nth-child(${fieldIndex + 1}) .typed-text`;this.$nextTick(() => {const element = this.$el.querySelector(elementSelector);if (element) {let i = 0;element.textContent = '';const typingInterval = setInterval(() => {if (i < text.length) {element.textContent += text.charAt(i);i++;} else {clearInterval(typingInterval);}}, 50); // 控制打字速度}});});
}

配合 CSS 实现光标闪烁效果:

.typed-text {border-right: 2px solid #333;padding-right: 3px;animation: blink 0.7s step-end infinite;
}@keyframes blink {from, to { border-color: transparent }50% { border-color: #333 }
}

3、案例效果

在控制台查看长连接实时传递数据

总结

SSE 是一种简单高效的服务器推送技术,非常适合只需要服务器向客户端单向发送数据的场景。与 WebSocket 相比,它实现简单且基于 HTTP 协议,无需额外的服务器配置。

本文只是一个简单的案例,有不足之处还请大家点出。

http://www.dtcms.com/a/422563.html

相关文章:

  • Web典型路由结构之Next.js (App Router, v13+) )(文件系统驱动的路由:File-based Routing)声明式路由:文件即路由
  • 【设计模式】解释器模式
  • 【前端知识】iframe 使用详细说明
  • 推荐一款集成AI功能的数据库管理工具
  • Flask 入门:轻量级 Python Web 框架的快速上手
  • 每日前端宝藏库 | tinykeys ✨
  • 第7章:TS快速入门和前端项目初始化
  • 合肥 做网站的深圳办公室装修设计公司
  • Android实现RecyclerView粘性头部效果,模拟微信账单列表的月份标题平移
  • 建三江建设局网站网站建设自我评价怎么写比较好
  • 华为Fit4手表:个性化表盘,让生活更有温度
  • Spring Boot - 从PF4J到SBP:深入解析Java插件化架构的演进与实践
  • 河南做网站企起做平面什么网站的素材不侵权
  • 哪个网站做ppt模板赚钱手机棋牌游戏平台
  • 鸿蒙app开发中 拿到json文件数据进行动画的播放
  • 第三章 鸽巢原理
  • 智慧政务——解读57页清华大学:DeepSeek政务场景应用与解决方案【附全文阅读】
  • Transformer模型:深度解析自然语言处理的革命性架构
  • 声网AI逐字拆解问题,30天重塑口语清晰表达
  • Java异常简介
  • VSCode Web版本安装
  • 实用软件 | 实时监控andriod设备硬件状态-devcheck
  • 非关系型数据库(NoSQL):特性、类型与应用指南​
  • 性能革命的底层逻辑:深入理解 Spring Cloud Gateway 的 Reactor 核心
  • 2025 年 AI+BI 趋势下,Wyn 商业智能软件如何重构企业决策效率?
  • 网站开发合同印花税公司网站建设重点内容
  • CMake cmake_parse_arguments
  • 4、存储系统架构 - 从机械到闪存的速度革命
  • 淘宝店铺全量商品接口深度开发:从分页优化到数据完整性保障
  • 视频MixformerV2 onnx导出