Server-sent Events 实现实时通信原理解析

前言

在 web 开发中,实时通信这个需求很常见,在传统的前后端交互中,通常都是前端通过轮询或者长轮询来实现实时通信,但这样会引起很多不必要的请求,严重拖累了服务器性能。

Server-sent Events (简称 SSE) 可以实现客户端与服务器的实时通信,利用浏览器默认存在的 EventSource 对象可以全双工地与已经建立的 http 长连接通信。SSE 数据传输只需要普通的 HTTP GET 请求,因此 SSE 也被称为 HTTP 流。

SSE 实现原理

SSE 的实现原理是在客户端发起一个简单的 HTTP GET 请求,服务器返回的是一个数据流,这个数据流通常是一个持续打开的 HTTP 连接,返回的数据格式是纯文本格式,基于标准化的 MIME 类型 text/event-stream,由 sever 端通过发送统一的格式化的消息来更新客户端,而客户端通过内置的浏览器对象的 onmessage 方法进行事件处理。

当客户端与服务器建立 SSE 连接后,如果连接一直保持开放状态,服务器就可以发送消息给客户端,客户端可以随时接收到信息而不需要刷新页面。当连接关闭后,客户端会自动重新连接,直到又建立了一个新的连接为止。SSE 连接的过程如下:

SSE 代码示例

下面是一个简单的 SSE 实现示例,通过 Node.js 服务端可实现将获取到的时间推送给客户端。

服务端代码:

const http = require('http');

http.createServer((req, res) => {
  console.log('server connected');
  res.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache',
    'Connection': 'keep-alive'
  });

  setInterval(() => {
    const time = new Date().toLocaleTimeString();
    const data = `data: ${time}\n\n`;
    res.write(data);
  }, 1000);
}).listen(3000);

console.log('SSE server started at http://localhost:3000');

客户端代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>SSE 实时通信示例</title>
</head>
<body>
  <h1>SSE 实时通信示例</h1>
  <hr>
  <div id="time"></div>
  <script>
    const eventSource = new EventSource('http://localhost:3000/');
    eventSource.addEventListener('message', (event) => {
      const time = event.data;
      document.querySelector('#time').innerHTML = time;
    });
  </script>
</body>
</html>

在服务端运行 node app.js(假设代码文件名称为 app.js),在浏览器中打开客户端代码,即可实现通过 SSE 实现实时通信。

总结

SSE 与 WebSocket 相比,SSE 需要的网络请求更少且网络负载更小,且不需要特殊的服务器配置。SSE 所传送的信息类型比 WebSocket 更简单,仅支持纯文本格式,而 WebSocket 可以支持任何格式的消息。但相对来说,SSE 更容易实现,不需要额外的库或者协议支持,而 WebSocket 需要额外的技术支持。

PS:需要注意的是,SSE 并不是所有浏览器都支持,所以在使用 SSE 时,需要做好浏览器兼容性问题。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65b70f2dadd4f0e0fffa9195