SSE是啥?如何使用?

SSE简介

sse是一个由后端主动向前端推送数据的单向通讯协议。具体介绍可查看mdn

优点:

  • 相比于websocket会更轻量。
  • 使用http协议,现在服务端都支持。
  • 可自动重连。

缺点:

  • 单向连接,前端若要与后端通信需配合其它请求。
  • 只能传递文本数据。

使用

通过new一个EventSource创建sse实例:

javascript 复制代码
let source = new EventSource(url);

source.readyState可以获取当前连接的状态:

  • 0:表示连接未建立或离线
  • 1:表示连接正常,可以接收数据
  • 2:表示连接关闭且不会重新连接

SSE有三个重要的事件,分别为:

  • open(当连接打开时,会执行此回调)
  • message(当客户端接收到数据的时候触发)
  • error(当通信发生异常的时候,会触发此事件)。

后端实现

这你我们使用express框架简单实现

  • 应设置长连接的响应头。
  • 返回数据,这里应注意返回的数据格式是固定的。每行数据以 \n 结尾,完结数据以 \n\n 结尾。retry 表示重新连接的延迟。 id 作为这条数据的唯一标识。
  • 监听 close 事件,当客户端使用source.close()关闭连接的时候可以触发此方法。
javascript 复制代码
app.get("/sse", (req, res) => {
  res.set({
    'Content-Type': 'text/event-stream', //设定数据类型
    'Cache-Control': 'no-cache',// 长链接拒绝缓存
    'Connection': 'keep-alive' //设置长链接
  });
  //持续返回数据
  const timer = setInterval(() => {
    const data = {
      message: `Current time is ${new Date().toLocaleTimeString()}`
    };
    res.write('retry: 10000\n')
    res.write(`id: ${Date.now()}\n`)
    res.write(`data: ${JSON.stringify(data)}\n\n`);
  }, 1000);
  if (!timer) res.write("data: 没有长连接\n\n");
  res.socket.on('close', () => {
    console.log("长连接关闭了")
    clearInterval(timer);
  })
})

前端实现

html 复制代码
// index.html
<button id="btn_start">点击开始连接服务</button>
<button id="btn_stop">关闭连接</button>
<ul id="list"></ul>
<script src="./index.js"></script>

使用 EventSource 创建一个长连接实例,入参为后端长连接url。当接收到消息时,在页面中创建 li 元素,并把获取到的信息展示到页面中。

javascript 复制代码
// index.js
const btn_start = document.getElementById("btn_start");
const btn_stop = document.getElementById("btn_stop");

//生成li元素
function createLi(data) {
  let li = document.createElement("li");
  li.innerHTML = String(data.message);
  document.getElementById("list").appendChild(li)
}

let source = ''

btn_start.addEventListener("click", function () {
  //判断当前浏览器是否支持SSE
  if (!window.EventSource) {
    alert("当前浏览器不支持SSE")
    throw new Error("当前浏览器不支持SSE")
  }
  source = new EventSource('http://localhost:8088/sse/');
  source.onopen = onConnectOpen;
  source.onmessage = onConnectMessage;
  source.onerror = onConnectError;
});

btn_stop.addEventListener("click", function () {
  if (source) source.close();
  console.log("长连接关闭");
});

// //对于建立链接的监听
function onConnectOpen(event) {
  console.log(source);
  console.log("长连接打开", event);
};

//对服务端消息的监听
function onConnectMessage(event) {
  console.log(JSON.parse(event.data));
  console.log("收到长连接信息", event);
  createLi(JSON.parse(event.data));
};

//对断开链接的监听
function onConnectError(event) {
  console.log(source, source.readyState);
  console.log("长连接中断", event);
};

其他

通过上述案例可以了解SSE的基础知识,当看到返回的仅仅是字符串时,也许会产生"只能用来传一些JSON数据"的感觉,其实大部分时候是这样的。但它也可以用来做大文件分片下载,试想一下:如果后端通过SSE对文件进行分片,然后转成base64的编码传递给前端,前端再把base64转成二进制,通过创建url以Blob为入参,就可以获取到下载这个大文件的url,进而处理相关逻辑。

这样做的有一个缺点,既然是大文件,当前端把所有文件块获取到的时候会占用很大内存,所以下载大文件得用流式下载的方法,最简单的是给 a 标签赋予 url,触发浏览器动作去下载,这样的话后端其实不必使用这种方式处理,所以这个例子只是作为一个可行性的分析,实际中不推荐。

注: 当不使用 HTTP/2时,打开长连接是有数量限制的,最多为6���

往期年度总结

往期文章

专栏文章

相关推荐
WebGIS皮卡茂24 分钟前
【数据可视化】Arcgis api 4.x 专题图制作之分级色彩,采用自然间断法(使用simple-statistics JS数学统计库生成自然间断点)
javascript·arcgis·信息可视化·前端框架
api771 小时前
1688商品详情API返回值中的售后保障与服务信息
java·服务器·前端·javascript·python·spring·pygame
赵广陆1 小时前
SprinBoot+Vue门诊管理系统的设计与实现
前端·javascript·vue.js·spring boot·maven
华山令狐虫2 小时前
el-tabs 样式修改
前端
Python私教2 小时前
JavaScript 基于生成器的异步编程方案相关代码分享
android·javascript·okhttp
Bob99982 小时前
电脑浏览器访问华为路由器报错,无法访问路由器web界面:ERR_SSL_VERSION_OR_CIPHER_MISMATCH 最简单的解决办法!
开发语言·javascript·网络·python·网络协议·华为·ssl
史努比的大头4 小时前
前端开发深入了解webpack
前端
Dovir多多4 小时前
渗透测试入门学习——php与mysql数据库连接、使用session完成简单的用户注册、登录
前端·数据库·后端·mysql·安全·html·php
B.-4 小时前
Remix 学习 - @remix-run/react 中主要的 hooks
前端·javascript·学习·react.js·web
2302_802836164 小时前
JS考核答案
javascript