消息推送是指服务端项客户端主动推送消息。
严格地说,HTTP 协议无法做到服务器主动推送信息。但是,有一种变通方法,就是服务器向客户端声明,接下来要发送的是流信息(streaming)。也就是说,发送的不是一次性的数据包,而是一个数据流,会连续不断地发送过来。这时,客户端不会关闭连接,会一直等着服务器发过来的新的数据流,视频播放就是这样的例子。本质上,这种通信就是以流信息的方式,完成一次用时很长的下载。SSE 就是利用这种机制,使用流信息向浏览器推送信息。SSE基于 HTTP 协议中的持久连接,具有由 W3C 标准化的网络协议和 EventSource 客户端接口,作为 HTML5 标准套件的一部分,目前除了 IE/Edge,其他浏览器都支持。
if ('EventSource' in window) {}
var source = new EventSource(url,{ withCredentials: true });
0:相当于常量EventSource.CONNECTING,表示连接还未建立,或者断线正在重连。
1:相当于常量EventSource.OPEN,表示连接已经建立,可以接受数据。
2:相当于常量EventSource.CLOSED,表示连接已断,且不会重连。
// 写法一
source.onopen = function (event) {
};
// 写法二
source.addEventListener('open', function (event) {
}, false);
// 写法一
source.onmessage = function (event) {
var data = event.data;
};
// 写法二
source.addEventListener('message', function (event) {
var data = event.data;
}, false);
// 写法一
source.onerror = function (event) {
};
// 写法二
source.addEventListener('error', function (event) {
}, false);
source.close();
source.addEventListener('自定义 SSE 事件', function (event) {
var data = event.data;
}, false);
sse封装
class SseClient {
sseUrl = ''
source = null;
openCallback = null;
errorCallback = null;
messageCallback = null;
constructor(sseUrl, openCallback, errorCallback, messageCallback) {
this.sseUrl = sseUrl
this.openCallback = openCallback
this.errorCallback = errorCallback
this.messageCallback = messageCallback
this.connect()
}
connect() {
if ('EventSource' in window) {
// sseUrl可以与当前网址同域,也可以跨域。跨域时,可以指定第二个参数,打开withCredentials属性,表示是否一起发送 Cookie
this.source = new EventSource(this.sseUrl)
// 连接一旦建立,就会触发open事件,可以在onopen属性定义回调函数
this.source.onopen = (event) => {
this.open(event)
}
// 如果发生通信错误(比如连接中断),就会触发error事件,可以在onerror属性定义回调函数。
this.source.onerror = (event) => {
this.error(event)
}
// 客户端收到服务器发来的数据,就会触发message事件,可以在onmessage属性的回调函数
this.source.onmessage = (event) => {
this.message(event)
}
} else {
alert('当前浏览器不支持SSE!')
}
}
open(event) {
this.openCallback && this.openCallback(event)
}
error(event) {
this.errorCallback && this.errorCallback(event)
}
message(event) {
this.messageCallback && this.messageCallback(event)
}
}
/**
* 监听SSE的通用方法
* @param sseUrl:SSE的连接地址
* @param openCallback:SSE连接成功建立时的回调函数
* @param errorCallback:SSE发生通信错误时的回调函数
* @param messageCallback:客户端收到服务器发来数据时的回调函数
* @returns {SseClient}
*/
export default (sseUrl, openCallback, errorCallback, messageCallback) => {
return new SseClient(sseUrl, openCallback, errorCallback, messageCallback)
}
调用
connectSSE() {
this.sse = SseClient('http://127.0.0.1:8844/stream', this.open, this.error, this.message)
},
open(event) {
console.log('open', event)
},
error(event) {
console.log('error', event)
},
message({ data }) {
console.log(data)
},
var http = require("http");
http.createServer(function (req, res) {
var 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": '*',
});
// 服务器可以用retry字段,指定浏览器重新发起连接的时间间隔
res.write("retry: 10000\n");
// event字段表示自定义的事件类型,默认是message事件。浏览器可以用addEventListener()监听该事件。
// 自定义connecttime事件
res.write("event: connecttime\n");
// 数据内容用data字段表示。
res.write("data: " + (new Date()) + "\n\n");
res.write("data: " + (new Date()) + "\n\n");
interval = setInterval(function () {
res.write("data: " + (new Date()) + "\n\n");
}, 1000);
req.connection.addListener("close", function () {
clearInterval(interval);
}, false);
}
}).listen(8844, "127.0.0.1");
vue-sse