JS EventSource 使用详解

73 min read

EventSource 是一种用于从服务器端接收实时事件的 Web API。它可以向浏览器端发送即时更新的数据,这对于需要实时交互的应用程序非常有用。这篇文章将详细介绍 EventSource 的使用。

基本概念

在理解 EventSource 的使用之前,需要了解几个基本概念。

服务器推送

服务器推送是指服务器将数据或事件实时推送到客户端,而不是等待客户端的请求。这种推送方式可以提高客户端与服务器之间的响应速度和实时性。

SSE

EventSource 使用 Server-Sent Events(简称 SSE)协议与服务器进行通信。SSE 协议是一种单向通信协议,它允许服务器向客户端发送事件。SSE 中的每个事件都包含一个标识符、一个类型和数据字段。

使用方法

创建 EventSource 实例

要使用 EventSource,需要首先创建一个 EventSource 实例:

const eventSource = new EventSource(url);

其中,url 参数是指向 SSE 服务器的 URL。

监听事件

一旦创建了 EventSource 实例,就可以通过 onopenonmessageonerror 属性来监听事件。 onopen 事件在和服务器建立 SSE 连接时触发; onmessage 事件在接收到 SSE 事件时触发,可以通过 data 属性获取事件数据; onerror 事件在建立 SSE 连接或接收 SSE 事件时出现错误时触发。

例如,可以这样监听事件:

eventSource.onopen = e => {
  console.log('SSE connection opened');
};

eventSource.onmessage = e => {
  const data = JSON.parse(e.data);
  console.log(`Received ${data.message} from server`);
};

eventSource.onerror = e => {
  console.error('SSE connection failed');
};

发送事件

要向客户端发送事件,服务器需要按照 SSE 协议发送数据。可以使用 text/event-stream MIME 类型和 data 字段来发送数据。

例如,以下是一个简单的 PHP 脚本,用来向客户端发送 SSE 事件:

header("Content-Type: text/event-stream\n\n");

$data = array(
  'message' => 'Hello, world!',
  'timestamp' => time()
);

echo 'data: ' . json_encode($data) . "\n\n";

在这个脚本中,header() 函数设置了 MIME 类型为 text/event-stream,并且发送了一个包含数据的 SSE 事件。

关闭连接

使用 close() 方法可以关闭 SSE 连接:

eventSource.close();

示例

以下是一个简单的例子,演示了如何使用 EventSource 实现实时计时器。这个计时器将在客户端每秒更新一次。

HTML

<!DOCTYPE html>
<html>
  <head>
    <title>Real-time Timer</title>
  </head>
  <body>
    <h1 id="timer">00:00:00</h1>
    <script src="app.js"></script>
  </body>
</html>

JavaScript

const eventSource = new EventSource('timer.php');

eventSource.onopen = e => {
  console.log('SSE connection opened');
};

eventSource.onmessage = e => {
  const data = JSON.parse(e.data);
  const timerElement = document.getElementById('timer');

  const minutes = Math.floor(data.seconds / 60);
  const seconds = data.seconds % 60;
  const hours = Math.floor(minutes / 60);

  const formattedTime = `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
  timerElement.textContent = formattedTime;
};

eventSource.onerror = e => {
  console.error('SSE connection failed');
};

PHP

header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');

$time = time() - $_SERVER['REQUEST_TIME'];

while (1) {
  $data = array(
    'seconds' => $time
  );

  $event = 'data: ' . json_encode($data) . "\n\n";

  echo $event;
  ob_flush();
  flush();

  sleep(1);
  $time++;
}

在这个例子中,客户端每秒钟会从服务器端接收到 SSE 事件,其中包含了已经过去的秒数。客户端将秒数转换为格式化的时间字符串,然后将其显示在页面上。

总结

EventSource 是一个非常有用的 Web API,可以让服务器和客户端直接进行实时通信。使用 EventSource 可以大大提高应用程序的实时性和动态性。