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

实时消息推送(Websocket/SSE)

实时消息推送(Websocket/SSE)

在日常的开发中,我们经常能碰见服务端需要主动推送给客户端数据的业务场景,比如数据大屏的实时数据,比如消息中心的未读消息,比如聊天功能等等。

本文主要介绍SSE的使用场景和如何使用SSE。

服务端向客户端推送数据的实现方案有哪几种?

我们常规实现这些需求的方案有以下三种

  • 轮询

  • websocket

  • SSE

轮询简介

在很久很久以前,前端一般使用轮询来进行服务端向客户端进行消息的伪推送,为什么说轮询是伪推送?因为轮询本质上还是通过客户端向服务端发起一个单项传输的请求,服务端对这个请求做出响应而已。通过不断的请求来实现服务端向客户端推送数据的错觉。并不是服务端主动向客户端推送数据。

显然,轮询一定是上述三个方法里最下策的决定。

轮询的缺点:

  • 首先轮询需要不断的发起请求,每一个请求都需要经过http建立连接的流程(比如三次握手,四次挥手),是没有必要的消耗。

  • 客户端需要从页面被打开的那一刻开始就一直处理请求。虽然每次轮询的消耗不大,但是一直处理请求对于客户端来说一定是不友好的。

  • 浏览器请求并发是有限制的。比如Chrome 最大并发请求数目为 6,这个限制还有一个前提是针对同一域名的,超过这一限制的后续请求将会被阻塞。而轮询意味着会有一个请求长时间的占用并发名额。

  • 而如果轮询时间较长,可能又没有办法非常及时的获取数据

websocket简介

websocket是一个双向通讯的协议,他的优点是,可以同时支持客户端和服务端彼此相互进行通讯。功能上很强大。

缺点也很明显,websocket是一个新的协议,ws/wss。也就是说,支持http协议的浏览器不一定支持ws协议。

相较于SSE来说,websocket因为功能更强大。结构更复杂。所以相对比较重。

websocket对于各大浏览器的兼容性↓

图片

SSE简介

sse是一个单向通讯的协议也是一个长链接,它只能支持服务端主动向客户端推送数据,但是无法让客户端向服务端推送消息。

长链接是一种HTTP/1.1的持久连接技术,它允许客户端和服务器在一次TCP连接上进行多个HTTP请求和响应,而不必为每个请求/响应建立和断开一个新的连接。长连接有助于减少服务器的负载和提高性能。

SSE的优点是,它是一个轻量级的协议,相对于websockte来说,他的复杂度就没有那么高,相对于客户端的消耗也比较少。而且SSE使用的是http协议(websocket使用的是ws协议),也就是现有的服务端都支持SSE,无需像websocket一样需要服务端提供额外的支持。

注意:IE大魔王不支持SSE

SSE对于各大浏览器的兼容性↓

图片

上图是SSE对于浏览器的兼容不是对于服务端的兼容。

websocket和SSE有什么区别?

轮询

对于当前计算机的发展来说,几乎很少出现同时不支持websocket和sse的情况,所以轮询是在极端情况下浏览器实在是不支持websocket和see的下策。

Websocket和SSE

我们一般的服务端和客户端的通讯基本上使用这两个方案。首先声明:这两个方案没有绝对的好坏,只有在不同的业务场景下更好的选择。

SSE的官方对于SSE和Websocket的评价是

  • WebSocket是全双工通道,可以双向通信,功能更强;SSE是单向通道,只能服务器向浏览器端发送。

  • WebSocket是一个新的协议,需要服务器端支持;SSE则是部署在HTTP协议之上的,现有的服务器软件都支持。

  • SSE是一个轻量级协议,相对简单;WebSocket是一种较重的协议,相对复杂。

  • SSE默认支持断线重连,WebSocket则需要额外部署。

  • SSE支持自定义发送的数据类型。

Websocket和SSE分别适用于什么业务场景?

对于SSE来说,它的优点就是轻,而且对于服务端的支持度要更好。换言之,可以使用SSE完成的功能需求,没有必要使用更重更复杂的websocket。

比如:数据大屏的实时数据,消息中心的消息推送等一系列只需要服务端单方面推送而不需要客户端同时进行反馈的需求,SSE就是不二之选。

对于Websocket来说,他的优点就是可以同时支持客户端和服务端的双向通讯。所适用的业务场景:最典型的就是聊天功能。这种服务端需要主动向客户端推送信息,并且客户端也有向服务端推送消息的需求时,Websocket就是更好的选择。

SSE有哪些主要的API?

建立一个SSE链接 :var source = new EventSource(url);

SSE连接状态

source.readyState
  • 0,相当于常量 EventSource.CONNECTING,表示连接还未建立,或者连接断线。

  • 1,相当于常量 EventSource.OPEN,表示连接已经建立,可以接受数据。

  • 2,相当于常量 EventSource.CLOSED,表示连接已断,且不会重连。

SSE相关事件

  • open事件(连接一旦建立,就会触发open事件,可以定义相应的回调函数)

  • message事件(收到数据就会触发message事件)

  • error事件(如果发生通信错误(比如连接中断),就会触发error事件)

数据格式

Content-Type: text/event-stream //文本返回格式
Cache-Control: no-cache  //不要缓存
Connection: keep-alive //长链接标识

SSE相关文档:

https://www.w3cschool.cn/nwfchn/wpi3cozt.html

显然,如果直接看api介绍不论是看这里还是看官网,大部分同学都是比较懵圈的状态,那么我们写个demo来看一下?

“我更建议您先把Demo跑起来,然后在看看上面这个w3cschool的SSE文档。两个配合一起看,会更方便理解些。

如何实操一个SSE链接?Demo

这里Demo前端使用的就是最基本的html静态页面连接,没有使用任何框架。

后端选用语言是node,框架是Express。

理论上,把这两段端代码复制过去跑起来就直接可以用了。

  • 第一步,建立一个 index.html文件,然后复制前端代码Demo到index.html文件中,打开文件

  • 第二步,进入一个新的文件夹,建立一个 index.js文件,然后将后端Demo代码复制进去,然后在该文件夹下执行

npm init          //初始化npm       
npm i express     //下载node express框架
node index        //启动服务

图片

在这一层文件夹下执行命令。

完成以上操作就可以把项目跑起来了

前端代码Demo

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
 6     <meta name="viewport" content="width=device-width, initial-scale=1.0">
 7     <title>Document</title>
 8 </head>
 9 <body>
10     <ul id="ul">
11         
12     </ul>
13 </body>
14 <script>
15 16 //生成li元素
17 function createLi(data){
18     let li = document.createElement("li");
19     
20             li.innerHTML
21            = String(
22             data.message);
23           
24     return li;
25 }
26     
27 //判断当前浏览器是否支持SSE
28 let source = ''
29 if (!!window.EventSource) {
30     source = new EventSource('http://localhost:8088/sse/');
31  }else{
32     thrownewError("当前浏览器不支持SSE")
33  }
34 35 //对于建立链接的监听
36  
37             source.onopen
38            = function(event) {
39    console.log(
40             source.readyState);
41           
42    console.log("长连接打开");
43  };
44 45 //对服务端消息的监听
46  
47             source.onmessage
48            = function(event) {
49    console.log(JSON.parse(
50             event.data));
51           
52    console.log("收到长连接信息");
53    let li = createLi(JSON.parse(
54             event.data));
55           
56    document.getElementById("ul").appendChild(li)
57  };
58 59 //对断开链接的监听
60  
61             source.onerror
62            = function(event) {
63    console.log(
64             source.readyState);
65           
66    console.log("长连接中断");
67  };
68 69 </script>
70 </html>

 

后端代码Demo(node的express)

 1 const express = require('express'); //引用框架
 2 const app = express(); //创建服务
 3 const port = 8088; //项目启动端口
 4  5 //设置跨域访问
 6  7             app.all(
 8           "*", function(req, res, next) {
 9 //设置允许跨域的域名,*代表允许任意域名跨域
10  
11             res.header(
12           "Access-Control-Allow-Origin", '*');
13 //允许的header类型
14  
15             res.header(
16           "Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With");
17 //跨域允许的请求方式 
18  
19             res.header(
20           "Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
21 // 可以带cookies
22  
23             res.header(
24           "Access-Control-Allow-Credentials", true);
25 if (
26             req.method
27            == 'OPTIONS') {
28   
29             res.sendStatus(
30           200);
31  } else {
32   next();
33  }
34 })
35 36             app.get(
37           "/sse",(req,res) => {
38     
39             res.set({
40           
41         'Content-Type': 'text/event-stream', //设定数据类型
42         'Cache-Control': 'no-cache',// 长链接拒绝缓存
43         'Connection': 'keep-alive'//设置长链接
44       });
45 46       console.log("进入到长连接了")
47       //持续返回数据
48       setInterval(() => {
49         console.log("正在持续返回数据中ing")
50         const data = {
51           message: `Current time is ${new Date().toLocaleTimeString()}`
52         };
53         
54             res.write(
55           `data: ${JSON.stringify(data)}\n\n`);
56       }, 1000);  
57 })
58 59 //创建项目
60 61             app.listen(port,
62            () => {
63 console.log(`项目启动成功-http://localhost:${port}`)
64 })

 

总结

  • SSE比websocket更轻

  • SSE是基于http/https协议的

  • websocket是一个新的协议,ws/wss协议

  • 如果只需要服务端向客户端推送消息,推荐使用SSE

  • 如果需要服务端和客户端双向推送,请选择websocket

  • 不论是SSE还是websocket,对于浏览器的兼容性都不错

  • 轮询是下策,很占用客户端资源,不建议使用。(不过偷懒的时候他确实方便)

  • IE不支持SSE

对了,小程序不支持SSE哦

http://www.jsqmd.com/news/100661/

相关文章:

  • (Dify Tesseract 更新机制终极指南):构建高可用AI应用的基石
  • 无需力标定也能精准感知接触力?GelSight Mini光学触觉传感器迎来新校准范式
  • 智能Agent容器部署必看:5种常见资源配置错误及修复方案
  • godot引擎学习笔记4(C#)
  • 为什么你的Vercel AI SDK在Docker中无法读取环境变量?深度剖析加载机制盲区
  • 揭秘Docker MCP 网关负载均衡机制:5步实现无缝流量分发
  • 模温机企业排名:2025
  • 揭秘Dify重排序算法:如何选择最优模型提升搜索相关性?
  • 2025模温机厂家推荐排行榜:非标定制与专业服务
  • 肌营养不良新突破:固本培元生肌疗法
  • 【量子计算镜像构建缓存全解析】:掌握高效量子环境部署的5大核心技术
  • 加密文档处理生死战:Dify错误处理必须掌握的6项核心技术
  • 资源利用率下降30%?私有化Dify监控告警机制这样优化,稳了!
  • 【架构师亲授】:Docker MCP 网关服务注册的7大最佳实践
  • 找不到符号
  • Spring AI对接Dify的10个关键步骤,99%开发者忽略的部署细节
  • 【高危漏洞预警】:忽视Dify权限校验导致数据越权访问的5大案例
  • 为什么90%的企业还没意识到Dify解密算法对文档安全的颠覆性威胁?
  • Dify工作流依赖检查实战(从入门到精通)
  • arm中的ros项目交叉编译,一整套 业务级、完整、可直接用 的交叉编译 + rootfs 同步 + 自动上传 + 自动运行脚本 (未完全解决编译问题,大概编译到7%的时候报错,出现的问题应该在原)
  • Tesseract在Dify中的批量任务崩溃?99%的人都忽略的资源控制策略
  • 300套伺服电机步进调速电机SolidWorks三维3D模型图结构库合集
  • 错过再等十年:IPCC级气候归因模型R实现全过程首次公开
  • 编码器伺服电机例程代码原理图PMSM stm32 foc bldc学习资料
  • Agent与Dify集成深度解析(文档自动生成技术内幕)
  • 仅限内部分享:量子计算平台镜像最小化构建流程(限时公开)
  • 揭秘Dify模型私有化部署难题:如何实现秒级加载与稳定运行
  • 【高并发场景下的稳定性保障】:Dify混合检索缓存自动清理方案设计
  • 为什么你的帧提取总失败?,Dify帧率配置的3个隐藏规则曝光
  • 【Docker MCP 网关负载均衡实战指南】:掌握高可用架构设计核心秘诀