传统的Web前后台通讯主要是使用HTTP方式进行的,通常是前台需要什么就主动向后台请求,后台无法直接向前台发送数据。通常后台数据如果频繁变动的话前台主要靠 轮询 或是 长连接 方式来处理,两种方式相对来说都不是很优雅。
而到了现在有两种方案来处理这个问题: WebSocket 和 Server-sent events(SSE) 。 WebSocket 可以实现实时的双向通讯,功能上来说是非常强的,不过相对于HTTP而言是一种另起炉灶的技术。Server-sent events 则是在HTTP之上扩展出来的功能,有点像前面提到的 长连接 ,但是这是原生的标准,功能上更加完善,使用起来也更加方便。这篇文章将对 Server-sent events 相关内容做个说明。
Server-sent events 是H5中加入的功能,它是在HTTP上扩展出来的功能,使得服务器可以主动发送数据给客户端。在客户端使用 EventSource 接口来处理 Server-sent events 。
Server-sent events 最核心的其实就是新增了一个 MIME type : text/event-stream
。看名字就是知道这是一个流,只要不结束的的话就一直可以传数据。
实际使用中只要客户端主动发起访问接口,建立连接后就不用管了,服务器会在需要的时候主动推送消息。
Server-sent events 这种原生的功能有一个好处是浏览器端默认会自动重连。
客户端使用 EventSource 接口来处理 Server-sent events 。使用方法主要如下:
var es = new EventSource("/sse"); // 声明EventSource对象并连接url
es.onmessage = (e) => {} // 收到服务器消息时触发
es.onopen = (e) => {} // 连接建立时触发
es.onerror = (e) => {} // 发生错误时触发
// es.close(); // 关闭EventSource连接
// console.log(es.url);
// console.log(es.readyState); // 连接状态: 0 - connecting; 1 - open; 2 - closed;
客户端基本的使用是比较简单的,演示需要结合下面服务器进行。
对于前端来说直接使用JS的EventSource接口就可以使用SSE了,对于其它语言作为客户端来说可能没有现成的方法可用,但其实要用上也挺简单,使用 GET
方法访问链接,并在头文件中包含下面属性即可(只是建议,并不是必须):
accept: text/event-stream
cache-control: no-store
connection: keep-alive
这样就可以建立起连接了,之后等待并处理来自服务器的数据就行。
Server-sent events 是在HTTP上扩展出来的功能,所以服务器实现只需要在HTTP服务器的基础上稍作处理即可,最主要的就是设置响应头中 MIME type 为 text/event-stream
。下面是个最简单的例子:
const http = require('http')
const server = http.createServer((req, res) => {
// 访问链接 /sse
if (req.url == '/sse') {
res.writeHead(200, {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
"Connection": "keep-alive",
});
res.write("data: " + 'connected' + "\n\n");
// 服务器定期向客户端主动发消息
interval = setInterval(function () {
res.write("data: " + 'hello world' + "\n\n");
}, 5000);
// req.on('close', () => {}) // 客户端断开连接时触发
return
}
// 其它任何链接都返回网页
res.statusCode = 200
res.end(`
`)
})
server.listen(80, '127.0.0.1', () => {
console.log(`Server running at http://127.0.0.1/`)
})
上面例子中服务器在收到EventSource的连接请求后返回了 200
状态码,并在响应头中加入了 text/event-stream
,这些内容发送给客户端后连接就算建立完成了。之后只要有需要时服务器再向客户端发送消息即可,上面例子中使用定时器来模拟发送消息。
Server-sent events中服务器发送的数据必须是 UTF-8 编码的文本,还有一定的格式要求:
\n\n
,后一个换行符就提供 了空行data: 数据文本
上面提到的标识字段可选值如下:
data:
event:
id:
retry:
:
针对上面的一些内容可以使用下面方式进行测试:
const http = require('http')
const server = http.createServer((req, res) => {
// 访问链接 /sse
if (req.url == '/sse') {
console.log(req.headers);
res.writeHead(200, {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
"Connection": "keep-alive",
});
res.write("retry: 10000\n");
res.write("event: connected\n");
res.write("data: connected\n\n");
// 服务器定期向客户端主动发消息
interval = setInterval(function () {
res.write("data: " + "hello world" + "\n");
res.write("id: " + "aaa" + "\n\n");
res.write("event: " + "naisu" + "\n");
res.write("data: " + "233~~~" + "\n\n");
}, 5000);
return
}
// 其它任何链接都返回网页
res.statusCode = 200
res.end(`
`)
})
server.listen(80, '127.0.0.1', () => {
console.log(`Server running at http://127.0.0.1/`)
})
Server-sent events 虽然简单,但使用时还有一些事项需要注意:
Server-sent events的使用总的来说挺简单的,更多内容可以参考下面链接:
https://html.spec.whatwg.org/multipage/server-sent-events.html
http://www.ruanyifeng.com/blog/2017/05/server-sent_events.html