HTTP 服务器推送也称 HTTP 流,是一种客户端-服务器通讯模式,它将信息从 HTTP 服务器异步推送到客户端,而无需客户端请求。如今的 web 和 app 中,愈来愈多的场景使用这种通讯模式,好比实时的消息提醒,IM在线聊天,多人文档协做等。之前实现这种相似的功能通常都是用ajax长轮询,而如今咱们有了新的、更优雅的选择 —— WebSocket 和 SSE。javascript
WebSocket是HTML5开始提供的一种在单个 TCP 链接上进行全双工通信的协议。在WebSocket API中,浏览器和服务器只须要作一个握手的动做,而后,浏览器和服务器之间就造成了一条快速通道。二者之间就直接能够数据互相传送。浏览器经过 JavaScript 向服务器发出创建 WebSocket 链接的请求,链接创建之后,客户端和服务器端就能够经过 TCP 链接直接交换数据。当你获取 Web Socket 链接后,你能够经过 send() 方法来向服务器发送数据,并经过 onmessage 事件来接收服务器返回的数据。java
SSE 是 Server-Sent Events 的简称, 是一种服务器端到客户端(浏览器)的单项消息推送。对应的浏览器端实现 Event Source 接口被制定为HTML5 的一部分。不过如今IE不支持该技术。相比于 WebSocket,SSE 简单不少,服务器端和客户端工做量都要小不少、简单不少,同时实现的功能也要有局限。node
[Constructor(DOMString url, optional EventSourceInit eventSourceInitDict)]
interface EventSource : EventTarget {
readonly attribute DOMString url;
readonly attribute boolean withCredentials;
// ready state
const unsigned short CONNECTING = 0;
const unsigned short OPEN = 1;
const unsigned short CLOSED = 2;
readonly attribute unsigned short readyState;
// networking
attribute EventHandler onopen;
attribute EventHandler onmessage;
attribute EventHandler onerror;
void close();
};
dictionary EventSourceInit {
boolean withCredentials = false;
};
复制代码
var source = new EventSource(url)
复制代码
// 创建链接后,触发`open` 事件
source.onopen = (event)=>{
// ...
}
// 收到消息,触发`message` 事件
source.onmessage = (event)=>{
// ...
}
// 发生错误,触发`error` 事件
source.onerror = (event)=>{
// ...
}
// 自定义事件
source.addEventListener('eventName', event => {
// ...
}, false)
复制代码
source.close()
复制代码
SSE的相应,须要设置以下的Http头信息web
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
复制代码
第一行,Content-Type
指定的 MIME
类型必须为 text/event-stream
ajax
SSE 推送的消息必须是UTF-8
编码的纯文本。每次推送有若干个事件消息组成,每一个事件消息之间用两个换行(\n\n
)分割。每一个事件消息又有若干行组成,每行格式以键值对形式组成:express
[key]: value\n
复制代码
key
有一下几个值可取浏览器
addEventListener()
监听该事件。浏览器端代码bash
// index.js
var source = new EventSource('/stream');
source.onmessage = function(event) {
var message = event.data;
// do stuff based on received message
};
复制代码
服务器端代码(nodejs)服务器
var express = require('express')
var fs = require('fs')
var app = express()
app.get('/stream', (req, res) => {
res.writeHead(200, {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
"Connection": "keep-alive"
});
var interval = setInterval(function () {
res.write("data: " + (new Date()) + "\n\n");
}, 1000);
req.connection.addListener("close", function () {
clearInterval(interval);
}, false);
})
app.listen(9999, (err) => {
if (err) {
console.log(err)
return
}
console.log('listening on port 9999')
})
复制代码