在Web开发中,前后端交互是不可避免的。常见的方式有Ajax、WebSocket等。而本文将介绍一种被人们忽视的前端技术——Server-sent Events(SSE)。
什么是Server-sent Events
SSE是一个单向、基于HTTP协议的协议,目的是实现服务器向客户端推送数据。客户端通过EventSource对象监听服务器的事件,当发生事件时,服务器会将相关数据通过HTTP推送给客户端。
和WebSocket不同,SSE是长轮询的一种变种,它的工作流程如下:

优点:
- 相对于WebSocket的全双工协议,SSE对于简单的单向数据推送更适合。
- SSE支持跨域推送数据,可用于多个域的前端。
- SSE支持文本流,可以节省服务器带宽。
缺点:
- SSE不像WebSocket支持双向数据传输,所以无法作为交互性比较高的应用,比如聊天室。
- 联网失败后无法自动重连,需要手动处理。
如何使用Server-sent Events
在服务器端
首先需要告诉浏览器服务器的推送地址。可以通过添加HTTP头Content-Type:text/event-stream实现。如下:
// www.javascriptcn.com code example
const http = require('http');
const PORT = 3000;
const sse = (res) => {
// 服务器推送数据
const send = (data) => {
res.write(`event: hello\n`);
res.write(`data: ${data.toString()}\n\n`);
}
// 发送一个必要的头部,表明我们会向客户端发送 Server-Sent Events
res.setHeader('Content-Type', 'text/event-stream');
// 设置一个连接心跳,保持长连接不断开
res.write('retry: 10000\n\n');
// ********* 重要:发送一个消息保持连接 *********
let intervalID = setInterval(() => {
res.write(`:`);
}, 5000);
// ********* 处理路由 *********
const url = require('url');
const path = url.parse(req.url).pathname;
switch(path) {
case '/hello':
send({message: 'Hello World!'});
break;
default:
break;
}
}
// 启动 HTTP 服务
const server = http.createServer(function(req, res) {
sse(res);
});
server.listen(PORT, () => {
console.log(`Listening on port ${PORT}`);
});event: hello:事件名称(自定义)。data: "some data":实际的数据。retry: 1000:发现连接被关闭后隔多少毫秒重连。
在客户端
在使用SSE时,我们需要生成一个新的EventSource对象。例如:
// www.javascriptcn.com code example
if (typeof(EventSource) !== "undefined") {
var source = new EventSource("/hello");
source.onopen = function() {
console.log("Connection was opened");
};
source.onerror = function(e) {
console.log("Error encountered.");
};
source.addEventListener("hello", function(e) {
console.log(e.data);
}, false);
} else {
console.log("EventSource is not supported by your browser.");
}source.onopen:连接建立时调用的回调函数。source.onerror:出错时调用的回调函数。source.addEventListener:监听服务器推送的事件。
SSE与WebSocket的区别
- SSE是基于HTTP协议的单向通讯,WebSocket是双向通讯。
- SSE更轻量,性能更优越。而WebSocket超级灵活,可以进行大量的操作和扩展。
这里对比如下:

结语
SSE具有轻便、易用、跨域等优点,可以方便地使用在简单的通讯需求上。需要遵循的协议也相对简单。
这里附上一个简易版的示例:Server-Sent-Events实现
在使用中,我们需要注意:
- 协议格式,尤其是语法规则。
- 连接情况的判断及处理(心跳)。
- 永久连接的适用场景。
- 适用于需长时间运行并定时更新的应用程序。
虽然SSE的使用场景有所限制,但是它是一种比较方便、直接的单向推送数据的方法,建议熟练掌握。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67d66ecaa941bf7134c31eee