博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
server-side-events(SSE)开发指南(Node)
阅读量:7060 次
发布时间:2019-06-28

本文共 2477 字,大约阅读时间需要 8 分钟。

SSE是介于websocket、长短轮训之外的一种服务端推送的方式,用数据流的形式发送文本数据,可想象成网络视频的文字版。他的好处有

  • 使用简单,无需借助第三方库(如 )
  • 基于HTTP协议(WebSocket 是一个独立协议),无需对其做额外处理。还能享受HTTP2带来的优势
  • 默认支持断线重连
  • 支持自定义发送的消息类型

,这里我选择尝试将一个原本基于轮询的web app转到sse上来。虽然这套技术看上去使用很简单,但可能由于普及程度不高和资料较少的原因,在开发过程中会遇到很多的坑和要面临的新东西。这里帮大家总结一下,后端使用了koa.js(express应该会更简单)。

后端

对于一个SSE相应我们需要返回如下一些HTTP头

Content-Type: text/event-streamCache-Control: no-cache, no-transformConnection: keep-aliveX-Accel-Buffering: no复制代码

在其他的教程中提供的http头可能没有这里的全,区别主要在于:

  • Cache-Control中需要包含no-transform,没有这个的话在开发中,如果你用了create-react-app等工具来转发你的请求,那么你的数据流很可能被压缩,造成你怎么也收不到响应。这里当时排查了蛮久的()
  • no-transform是开发环境中的遇到的问题,但是在生产环境仍然还存在问题,比如我的网站使用nginx做反向代理的,默认会对应用的响应做缓冲(buffering),以至于我应用返回的消息没有立马发出去。所以我们需要给http头加上一条X-Accel-Buffering: no()

当设置好header后,我们就可以写入数据了。一般来说我们只需要监听数据的更新然后使用res.write即可写入数据:

const onEvent = function(data) {    res.write(`event: message\n`);    res.write(`data: ${
JSON.stringify(data)}\n\n`);};emitter.on('message', onEvent);复制代码

我们用\n来分隔每一行数据,用\n\n来分隔每一个事件。每一个事件中包含事件的type和事件的data,分别用两行来描述。比如上面是返回来一个message事件(若不指定事件类型,则默认message)。下图中我们还返回来一个withdraw事件,对应的数据行应该是event: withdraw

koa.js返回

对于koa情况比较复杂,官方不推荐我们直接操作res对象,而是给context(ctx)对象的body赋值。

其实我们只需要给ctx.body赋一个可写流,关于node流的概念可以看。如官方示例的:

/** * Create a transform stream that converts a stream * to valid `data: 
\n\n' events for SSE. */var Transform = require('stream').Transform;var inherits = require('util').inherits;module.exports = SSE;inherits(SSE, Transform);function SSE(options) { if (!(this instanceof SSE)) return new SSE(options); options = options || {}; Transform.call(this, options);}SSE.prototype._transform = function(data, enc, cb) { this.push(data.toString('utf8')); cb();};复制代码

注意官方实例中有个坑就是默认给每行数据前面加上了data:前缀,这里删除了。在使用const body = ctx.body = SSE()后就可以对body对象使用body.write了。详见官方实例,实例db.js文件中的可读流是可选项。

客户端

客户端(浏览器)的使用就非常简单了。大部分的浏览器支持SSE,而且我们有针对老浏览器的兼容方案,如。

使用上真的是特别的简单,而且几乎没有什么坑

const evtSource = new EventSource('/events'); evtSource.addEventListener('event', function(evt) {      const data = JSON.parse(evt.data);      // Use data here }, false);复制代码

上面的event可以替换为你的其他自定义事件。注意这里的连接中断后会自动重连,也许你需要监听onerror事件来做一些额外的处理()。导致中断的原因可能有时间间隔到期、网络错误等。你可以通过定时向客户端返回内容来避免间隔到期:

// Heartbeatconst nln = function() {    res.write('\n');};const hbt = setInterval(nln, 15000);// Clear heartbeat and listenerreq.on('close', function() {    clearInterval(hbt);    emitter.removeListener('event', onEvent);});复制代码

将轮询替换为sse后还是很清爽的。注意和websocket不同sse是单向数据流,我们在发送消息的时候需要使用其它的接口,可以通过node的来监听触发推送。

参考资料

转载地址:http://pdfll.baihongyu.com/

你可能感兴趣的文章
Linux -- 更改系统时区及时间
查看>>
浅谈reload,restart
查看>>
CSS彻底研究视频教程(全23讲)
查看>>
c标签的<c:choose><c:when>
查看>>
android 反汇编,修改,重新打包
查看>>
mysql服务命令
查看>>
Openstack 之 安全关闭HA集群
查看>>
Oracle新建用户、角色,授权,建表空间的sql语句
查看>>
SICP 3.28 3.29 3.30
查看>>
Beyond Compare怎么切换比较会话过滤模式
查看>>
MySQL 大数据操作注意事项
查看>>
学习HTML/CSS 第一天
查看>>
前端工程化之路(一)基于Yeoman:Yo+grunt/gulp+bower 搭建前端工程
查看>>
iOS设备发送语音信息相关功能代码
查看>>
AWSome Day大连站 安全狗云安全解决方案备受关注
查看>>
oracle同义词 创建,查询,删除
查看>>
关于spring mvc MaxUploadSizeExceededException 死循环解决方
查看>>
终于可以用Live Writer了
查看>>
用模式匹配解析 URL
查看>>
在学CI,基础OK,调用jquery的例子太少了。
查看>>