概述
服务器推送事件(Server-Sent Events,简称SSE),是浏览器向服务器发送一个HTTP请求后,服务器不断单向地向浏览器推送“信息”(message),本质上,这种通信是以流信息的方式完成的一次用时很长的下载。
特点
- SSE使用HTTP协议,现有的服务器软件都支持
- SSE属于轻量级,使用简单
- SSE默认支持断线重连
- SSE一般只用来传送文本,二进制数据需要编码后传送
- SSE支持自定义发送的消息类型
用法
客户端
-
EventSource 对象
SSE的客户端API部署在EventSource对象上,使用SSE时,浏览器首先生成一个EventSource实例,向服务器发起连接let source; if ('EventSource' in window) { source = new EventSource('/api/stream'); }EventSource可指定两个参数,url和withCredentials
url:EventSource实例的url属性返回连接的网址(请求地址)
withCredentials:EventSource实例的withCredentials属性返回一个布尔值,表示当前实例是否开启CORS的withCredentials,默认值是false -
readyState 属性
表明连接的当前状态,可取以下值:
0:相当于常量EventSource.CONNECTING,表示连接还未建立,或者断线正在重连
1:相当于常量EventSource.OPEN,表示连接已经建立,可以接受数据
2:相当于常量EventSource.CLOSED,表示连接已断,且不会重连 -
方法
open:连接一旦建立,就会触发
open事件,可在onopen属性定义回调函数source.onopen = function(event) { console.log('onopen event= ', event); }; // 另一种写法 source.addEventListener('open', function(event) { console.log('onopen event= ', event); }, false);error:如果发生通信发生错误或连接中断触发
error事件source.onerror = function(event) { console.log('onerror event= ', event); }; // 另一种写法 source.addEventListener('error', function(event) { console.log('onerror event= ', event); }, false);message:客户端收到服务器发送回来的数据就会触发
message事件source.onmessage = function(event) { console.log('onmessage event= ', event); }; // 另一种写法 source.addEventListener('message', function(event) { console.log('onmessage event= ', event); }, false);自定义事件:默认情况下,服务器发送回来的数据总是触发
message事件,我们可以自定义SSE事件,这种情况下,发送回来的数据不会触发message事件source.addEventListener('connecttime', function(event) { console.log('自定义事件:', event); }, false);close:用于关闭SSE连接
source.close(); -
代码
const _this = this; // 创建EventSource实例对象 const source = new EventSource('/api/stream'); // 连接一旦建立,调用该方法 source.onopen = function(event) { console.log('onopen= ', event); _this.isVisible = true; }; // 错误 source.onerror = function(event) { console.log('onerror= ', event); }; // 默认事件 source.onmessage = function(event) { console.log('onmessage= ', event.data); }; // 监听自定义progress方法 source.addEventListener('progress', function(event) { console.log('progress= ', event); _this.percentage = ~~event.data; if (_this.percentage >= 100) { // 关闭连接 source.close(); } }, false);
服务端
-
数据格式
服务端向浏览器发送的SSE数据,必须是UTF-8编码的文本,具有如下的HTTP头信息:
Content-Type: text/event-stream Cache-Control: no-cache Connection: keep-alive注:Content-Type必需指定为text/event-stream -
字段
每一次发送的信息,由若干个
message组成,每个message之间用\n\n分隔。每个message内部由若干行组成,每一行的格式如下:[field]: value\ndata:数据内容。
data: message\n\n如果数据很长,可以分成多行,最后一行用
\n\n分隔,中间每行用\ndata: begin message\n data: continue message\n\nJSON数据:
data: {\n data: data: [],\n data: message: '操作成功',\n data: status: 0\n data: }\n\nevent:表示自定义的事件类型,默认是
message事件。浏览器用addEventListener()监听。event: connecttime\n data: ${new Date()}\n\nid:数据标识符,相当于每一条数据的编号。浏览器用
lastEventId属性读取这个值。一旦连接断线,浏览器会发送一个HTTP头,里面包含一个特殊的Last-Event-ID头信息,用来帮助服务端重建连接。因此,这个头信息可以被视为一种同步机制。retry: 指定浏览器重新发起连接的时间间隔。
retry: 10000\n导致浏览器重新发起连接:
① 时间间隔到期
② 由于网络错误等原因,导致连接出错 -
代码
const http = require('http'); http.createServer(function(req, res) { let fileName = '.' + req.url; if (fileName === './stream') { res.writeHead(200, { "Content-Type": "text/event-stream", // 必需 "Cache-Control": "no-cache", "Connection": "keep-alive", "Access-Control-Allow-Origin": "*" }); // 指定浏览器重新发起连接的时间间隔:10s res.write('retry: 10000\n'); // 自定义事件:connecttime res.write(`event: connecttime\n`); // 自定义事件返回数据,以\n\n结束 res.write(`data: ${new Date()}\n\n`); let id = 0; let timer = setInterval(() => { // 默认事件标识符 res.write(`id: ${id++}\n`); // 默认事件返回数据 res.write(`data: ${new Date()}\n\n`); }, 1000); req.connection.addListener('close', function() { clearInterval(timer); }, false); } }).listen(3000, '127.0.0.1');