在前端开发中,服务器推送技术是非常重要的一部分,它允许 Web 应用程序向客户端推送更新,从而使 Web 应用程序更加动态和实时。其中一种服务器推送技术就是 Server-sent 事件(SSE)。本文将介绍 SSE 的实现原理以及如何使用 Node.js 来实现 SSE。
SSE 的实现原理
Server-sent 事件(SSE)是一个单向的持久连接,由服务器向客户端发送事件流。其基本工作原理是,浏览器向服务器发送一个 HTTP 请求,之后服务器通过持久连接发送事件流给客户端。当客户端收到事件流后,通过事件监听器监听每一个事件,并做出相应的操作。这个过程可以持续很久,直到连接被关闭。
SSE 的通信过程是基于 HTTP/1.1 的,使用的是长轮询(long-polling)机制。在传统的短轮询(short-polling)中,客户端定期向服务器发送请求,并获取服务器的响应。在长轮询中,客户端向服务器发送请求并保持连接打开,服务器保留请求打开,直到有新的数据可供发送时,再向客户端发送响应。
实现 SSE 的服务器端需要对 HTTP 响应头做出特殊的处理,以便浏览器可以正确解析 SSE 事件流。具体而言,服务器需要将 HTTP 响应头中的 Content-Type 设置为 text/event-stream;并且在返回的响应体中,每一条事件需要以固定格式进行编码:每个事件都以“data:”开始,后面跟着要发送的数据,每行末尾需要使用“\n\n”或“\r\r\n”进行结尾。服务器可以不定期地向客户端发送事件,每个事件对应一个 HTTP 响应。
用 Node.js 实现 SSE
Node.js 对 SSE 的支持非常友好,有一些第三方库可以轻松地实现基于 SSE 的服务器推送。这里我们以 EventSource 模块为例展示如何用 Node.js 实现 SSE。
首先,我们需要初始化一个 Node.js 的 HTTP 服务器,并为每个请求建立一个响应对象。在响应对象中我们需要设置 Content-Type 为 text/event-stream,并开启 TCP 连接:
// javascriptcn.com 代码示例 const http = require('http'); const server = http.createServer((req, res) => { res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Connection': 'keep-alive', 'Cache-Control': 'no-cache' }); // ... 创建 SSE 连接 ... }); server.listen(8080);
接下来,我们需要创建 SSE 连接,即为每个连接创建一个事件流,可以通过 EventSource 模块来实现:
const SSE = require('sse'); const sse = new SSE(server); sse.on('connection', (client) => { // ... 为连接创建事件流 ... });
在 SSE 连接上,我们可以创建多个事件流。为了创建事件流,我们需要设置一个 Heartbeat 定时器和一个事件监听器,来监听服务器是否有需要发送的数据,并通过事件流向客户端发送事件。代码如下:
// javascriptcn.com 代码示例 sse.on('connection', (client) => { const heartbeat = setInterval(() => { client.send('data: \n\n'); }, 15000); const dataListener = (data) => { client.send(`data: ${JSON.stringify(data)}\n\n`); }; // 添加事件监听器 emitter.on('event', dataListener); // 关闭 SSE 连接时,清除定时器和事件监听器 client.on('close', () => { clearInterval(heartbeat); emitter.off('event', dataListener); }); });
在每个事件流中,我们添加了一个 Heartbeat 定时器,它会定期地向客户端发送事件。同时,我们添加了一个事件监听器,它在服务器端有事件需要发送时会将数据通过事件流发送到客户端。在 SSE 连接关闭时,我们需要清除定时器和事件监听器,以免对服务器造成不必要的开销。
示例代码
展示了如何用 Node.js 实现 SSE 的示例代码:
// javascriptcn.com 代码示例 const http = require('http'); const SSE = require('sse'); const EventEmitter = require('events').EventEmitter; // 创建事件触发器 const emitter = new EventEmitter(); // 初始化 HTTP 服务器 const server = http.createServer((req, res) => { res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Connection': 'keep-alive', 'Cache-Control': 'no-cache' }); // 创建 SSE 连接 const sse = new SSE(req, res); // 为连接添加事件流 sse.on('connection', (client) => { const heartbeat = setInterval(() => { client.send('data: \n\n'); }, 15000); const dataListener = (data) => { client.send(`data: ${JSON.stringify(data)}\n\n`); }; // 添加事件监听器 emitter.on('event', dataListener); // 关闭 SSE 连接时,清除定时器和事件监听器 client.on('close', () => { clearInterval(heartbeat); emitter.off('event', dataListener); }); }); }); // 启动 HTTP 服务器 server.listen(8080); // 触发事件 setInterval(() => { emitter.emit('event', new Date()); }, 1000);
在这个示例中,我们创建了一个 HTTP 服务器,监听了一个端口号 8080。然后,我们创建一个 EventSource 对象,并绑定了一个连接监听器。在监听器中,我们创建了一个 Heartbeat 定时器和一个事件监听器。事件监听器监听一个名为 event 的事件,当有事件发送时,即向客户端发送一个包含数据的事件。最后,我们每隔 1 秒触发一次事件,来模拟服务器端有事件发生的情况。
总结
Server-sent 事件(SSE)是一种非常实用的服务器推送技术,它可以实现实时更新和更高的性能和优化。使用 Node.js 实现 SSE 很容易,只需要一些比较简单的编码即可。希望本文对您了解 SSE 有所帮助,感谢阅读!
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/653f3bdd7d4982a6eb8c38a7