hello~亲爱的看官老爷们大家好~过完年第一周已经结束,是时候开始制定新的工作计划了。主要负责的项目是数据可视化平台,而使用中如果服务器能有推送能力让页端得到相关通知的话,就能实现很多功能上的优化。鉴于项目中 Node 端已经正式投入使用,前端拥有了自己的服务器,搞事情起来自然方便很多。

技术选型:SSE(Server-sent Events) or WebSocket

若干年前,服务器并没有主动推送的能力,主要是通过轮询的方式来达到近似于服务器推送的能力。现在不需要这么麻烦,轮询只作为向下兼容的方案即可,当前主流的服务器推送是使用 SSE 或者 WebSocket 来实现的。两者对比如下:

是否基于新协议 是否双向通信 是否支持跨域 接入成本
SSE 否(Http 否(服务器单向) 否(Firefox 支持跨域)
WebSocket 是(ws

需要稍微解释一下的是接入成本。SSE 是相对轻量级的协议,(Node)代码实现上比较简单,而 WebSocket 是比较复杂的协议,虽然也有类库可以套用,也许页端方面两者代码量差不多,但服务器方面实现就复杂不少了。同时,要实现 WebSocket,是需要另起一个服务,而 SSE 并不需要。

比较之后,对 SSE 与 WebSocket 有了大致的理解。项目对服务器推送的要求是发送通知,而未来可能需要接入实时同步的功能,结合项目实际情况与接入成本后,选择了 SSE。

最后看一下浏览器支持情况以作参考:


IElet it go吧,日常不支持~其他浏览器还是绿油油的,支持度还是挺高的。

示例

Node端

项目中使用 Egg 作为框架,底层是 Koa2 的,因而使用 Koa2 作为示例。Node 端关键代码如下:

app.use(async (ctx) => {
const { res, request: { url } } = ctx;
res.writeHead(200, {
'Content-Type': 'text/event-stream', // 服务器声明接下来发送的是事件流
});
let stream = new PassThrough();
let i = 0;
let timer = setInterval(() => {
if (i === 5) {
stream.write('event: pause\n'); // 事件类型
} else {
stream.write('event: test\n'); // 事件类型
}
stream.write(`id: ${+new Date()}\n`); // 消息ID
stream.write(`data: ${i}\n`); // 消息数据
stream.write('retry: 10000\n'); // 重连时间
stream.write('\n\n'); // 消息结束
i++;
}, 1000); stream.on('close', function() {
console.log('closed.')
clearInterval(timer);
}) ctx.body = stream;
});

服务器告诉客户端,返回的类型是事件流(text/event-stream),查阅 MDN 文档可知:事件流仅仅是一个简单的文本数据流,文本应该使用 UTF- 8 格式的编码。每条消息后面都由一个空行作为分隔符。以冒号开头的行为注释行,会被忽略。

之后就是消息主体了,尽管例子使用 setInterval 模拟不断发送推送,但换成任意条件触发推送也是可以的。stream.write 调用了5次,对应规范中的各个字段,理解如下:

  • event 为消息的事件类型。客户端在 EventSource 中可以通过 addEventListener 收听相关的消息。该字段可省略,省略后客户端触发 message 事件。
  • id 为事件 ID。作为客户端内部的“最后一个事件 ID”的属性值,用于重连,不可省略。
  • data 为消息的数据字段,简单说就是客户端监听时间后,通过e.data 拿到的数据。
  • retry 为重连时间,可省略该参数。
  • 最后是结束该次通知的 \n\n,不可省略。除了上面规定的字段名,其他所有的字段名都会被忽略。

更详细的解释可以查阅 MDN 文档。有一个小细节需要注意,在 SSE 的草案中提到,"text/event-stream" 的 MIME 类型传输应当在静置 15 秒后自动断开。但实测(仅用了 Chrome)后发现,即使静置时间超过 15 秒,浏览器与客户端均不会断开连接。查阅了不少文章,均建议维护一套发送 \n\n 的心跳机制。个人认为此举有助于提高客户端程序的健壮性,但不是必须的。

最后是监听事件流的 close 事件,用于结束此次的链接。测试后发现,无论是让客户端调用 close 方法(下文有例子~),还是异常结束,包括关闭窗口、关闭程序等,都能触发服务器的 close 事件。

客户端

客户端代码更简单,示例如下:

const source = new EventSource('http://localhost:3000/test');

source.addEventListener('open', () => {
console.log('Connected');
}, false); source.addEventListener('message', e => {
console.log(e.data);
}, false); source.addEventListener('pause', e => {
source.close();
}, false);

前端童鞋对于这样的代码应该挺熟悉的,一切都是事件触发,根据不同的事件执行对应的代码。稍微说明一下 EventSource 拥有的属性和方法,相信大家就可以愉快地使用了。

EventSource 有三个默认的事件,分别是:

  • open:在连接打开时被调用。
  • message:收到一个没有 event 属性的消息时被调用。
  • error:当发生错误时被调用。

两个只读属性:

  • readyState:代表连接状态。可能值是CONNECTING (0), OPEN (1), 或者 CLOSED (2)。
  • url:代表连接的 URL。

一个方法:

  • close:调用后关闭连接(也就是上文所提及的)。

更详细的解释可以查阅 MDN 文档

小结

关于服务器 SSE 的简单介绍就到此为止了,可以看到,SSE 开发起来还是比较简单的,接入成本非常低。但并不是说 WebSocket 就是不好的,抛开实际场景谈业务就是耍流氓。此外上述代码只是演示,还能进一步进行优化的。如为了减轻服务器开销,可以建立一套机制有目的地断开与重连等,大家可以自行实现。

相关的代码已经丢到 Github 上,欢迎查阅。

感谢各位看官大人看到这里,知易行难,希望本文对你有所帮助~谢谢!

参考资料

20 行代码写一个数据推送服务

使用服务器发送事件

EventSource

服务器推送 SSE 了解一下?的更多相关文章

  1. SSE技术详解:一种全新的HTML5服务器推送事件技术

    前言 一般来说,Web端即时通讯技术因受限于浏览器的设计限制,一直以来实现起来并不容易,主流的Web端即时通讯方案大致有4种:传统Ajax短轮询.Comet技术.WebSocket技术.SSE(Ser ...

  2. 前端通信:SSE设计方案(二)--- 服务器推送技术的实践以及一些应用场景的demo(包括在线及时聊天系统以及线上缓存更新,代码热修复案例)

    距离上一篇博客,这篇文章的发布大概过了整整三个月.我也从饿了么度过了试用期,成为了正式员工.刚进来恰好遇到项目底层改造和迁移,将项目从angular全部迁移到vue上,所以适应这边的节奏和业务的开发任 ...

  3. HTML5中的SSE(服务器推送技术)

    本文原链接:https://cloud.tencent.com/developer/article/1194063 SSE技术详解:一种全新的HTML5服务器推送事件技术 前言 概述 基本介绍 与We ...

  4. SSE:服务器推送事件

    SSE:Server-Sent Event,服务器推送事件 常规的Http协议是一个请求对应一个响应的这种方式的 但对于某些实时性要求比较高的需求,HTML5中新增了SSE,可以很方便的实现局部数据的 ...

  5. HTML5 服务器推送事件(Server-sent Events)实战开发

    转自:http://www.ibm.com/developerworks/cn/web/1307_chengfu_serversentevent/ http://www.ibm.com/develop ...

  6. JavaEE开发之SpringMVC中的静态资源映射及服务器推送技术

    在上篇博客中,我们聊了<JavaEE开发之SpringMVC中的自定义拦截器及异常处理>.本篇博客我们继续的来聊SpringMVC的东西,下方我们将会聊到js.css这些静态文件的加载配置 ...

  7. HTML5 服务器推送事件(Server-sent Events)

    服务器推送事件(Server-sent Events)WebSocket 协议的一种服务器向客户端发送事件&数据的单向通讯.目前所有主流浏览器均支持服务器发送事件,当然除了 Internet ...

  8. 【SpringBoot】服务器端主动推送SSE技术讲解

    =====================16.高级篇幅之SpringBoot2.0服务器端主动推送SSE技术讲解 ============================ 1.服务端推送常用技术介绍 ...

  9. springweb flux 服务器推送事件

    以前做服务器推送一般用轮询,后端主动给客户端推送不是很好解决.有时候也可以采用websocket 现在看了springwebflux,用它自带的方法做服务器推送方便多了. 代码如下: import o ...

随机推荐

  1. java面试和笔试大全

    2.String是最基本的数据类型吗? 基本数据类型包括byte.int.char.long.float.double.boolean和short. java.lang.String类是final类型 ...

  2. D. Colored Boots(STL)

    There are nn left boots and nn right boots. Each boot has a color which is denoted as a lowercase La ...

  3. 看了这个Java实习生入职测试题后,幸亏我不是实习生

    看了这个Java实习生入职测试题后,幸亏我不是实习生 一个Java实习生的入职测试题,你能答对几个? 今天在某APP中看到,有实习生放出的Java实习生入职测试题.看完之后,很庆幸自己不是实习生. 本 ...

  4. IP命令介绍

    ip指令可以显示或操作路由.网络设备.设置路由策略和通道 1.语法 ip [选项]  Object  COMMAND [help] Object对象可以是: link  网络设备.addr 设备的协议 ...

  5. 扩增|feather evolution

    Wool vs feather 扩增方法:1.Gene Duplication2.Genome Duplication3.Cluster 哺乳动物毛发和鸟类的羽毛,都来自于角蛋白. 羽毛进化图 DNA ...

  6. vue2.0学习之路由

    下载vue-router: cnpm install vue-router --save router/main.js /*引入所需要的组件*/ import VueRouter from 'vue- ...

  7. python学习笔记(13)常用模块列表总结

    os模块: os.remove() 删除文件 os.unlink() 删除文件 os.rename() 重命名文件 os.listdir() 列出指定目录下所有文件 os.chdir() 改变当前工作 ...

  8. android完整智能家居、备忘录、蓝牙配对、3D动画库、购物车页面、版本更新自动安装等源码

    Android精选源码 app 版本更新.下载完毕自动自动安装 android指针式分数仪表盘 ANdroid蓝牙设备搜索.配对 Android 图片水印框架,支持隐形数字水印 android3D旋转 ...

  9. Archives: 2018/11

    There are 35 posts in total till now. 11月 11, 2018 HTTP 11月 11, 2018 TCP与UDP 11月 10, 2018 Python测试 1 ...

  10. motionbuilder卸载/完美解决安装失败/如何彻底卸载清除干净motionbuilder各种残留注册表和文件的方法

    在卸载motionbuilder重装motionbuilder时发现安装失败,提示是已安装motionbuilder或安装失败.这是因为上一次卸载motionbuilder没有清理干净,系统会误认为已 ...