概述
服务器推送事件(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
,表示连接已断,且不会重连 -
方法
onopen:连接一旦建立,就会触发open
事件,可在onopen
属性定义回调函数source.onopen = function(event) { console.log('onopen event= ', event); }; // 另一种写法 source.addEventListener('open', function(event) { console.log('onopen event= ', event); }, false); 复制代码
onerror:如果发生通信发生错误或连接中断触发
error
事件source.onerror = function(event) { console.log('onerror event= ', event); }; // 另一种写法 source.addEventListener('error', function(event) { console.log('onerror event= ', event); }, false); 复制代码
onmessage:客户端收到服务器发送回来的数据就会触发
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\n 复制代码
data:数据内容。
data: message\n\n 复制代码
如果数据很长,可以分成多行,最后一行用
\n\n
分隔,中间每行用\n
data: begin message\n data: continue message\n\n 复制代码
JSON数据:
data: {\n data: data: [],\n data: message: '操作成功',\n data: status: 0\n data: }\n\n 复制代码
event:表示自定义的事件类型,默认是
message
事件。浏览器用addEventListener()
监听。event: connecttime\n data: ${new Date()}\n\n 复制代码
id:数据标识符,相当于每一条数据的编号。浏览器用
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');
复制代码