为什么服务器发送的事件每 3 秒启动一次?

Why do server-sent events initiate every 3 seconds?

我是服务器发送事件的新手,所以我正在 WAMP 服务器上尝试 this W3Schools example。我拥有的文件是:

demo_sse.php

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

  $time = date('r');
  echo "data: The server time is: {$time}\n\n";
  flush();
?>

index.php

<!DOCTYPE html>
<html>
  <body>
    <h1>Getting server updates</h1>
    <div id="result"></div>
    <script>
      if(typeof(EventSource) !== "undefined") {
        var source = new EventSource("demo_sse.php");
        source.onmessage = function(event) {
          document.getElementById("result").innerHTML += event.data + "<br>";
        };
      } else {
        document.getElementById("result").innerHTML = "Sorry, your browser does not support server-sent events...";
      }
    </script>
  </body>
</html>

据我了解,时间在不断变化,因此必须每秒(至少)发送一次更新。但是,每三秒接收一次更新。此间隔未在 demo_sse.php 中指定,因此:

根据this article on the late, great HTML5 Rocks

The magical part is that whenever the connection is closed, the browser will automatically reconnect to the source after ~3 seconds. Your server implementation can even have control over this reconnection timeout. See Controlling the reconnection-timeout in the next section.

demo_sse.phpflush之后结束,所以连接关闭;浏览器将在 3(多)秒后自动重新连接。

要控制服务器上的重新连接超时,您可以在流中发送一个 retry 字段。从this MDN doc可以确定,如果你添加 echo "retry: 1000\n\n"; 行在 echo "data: 行之前,它将超时更改为 1 秒。

W3School 上的例子有点不好。

对于大多数 HTTP response/requests 交换,客户端向服务器发出 HTTP 请求,服务器发回数据,交换完成。

对于 SSE(尽管它仍然使用 HTTP 协议),这有点不同。在这里,客户端向服务器发出请求,会话保持打开状态,服务器可以随时发送数据。如果会话因任何原因关闭,EventSource 将尝试重新连接并且一切重新开始。

您的 PHP 脚本中的问题是脚本在完成最后一行后结束 request/response 交换。这意味着连接已关闭,因此 EventSource 将尝试重新连接。 (添加 .onerror 事件将显示在每条消息后都会引发错误。)

the specification 中所定义:

A reconnection time, in milliseconds. This must initially be a user-agent-defined value, probably in the region of a few seconds.

这就是您每三秒接收一次更新的原因。因为那是用户代理定义的值设置的内容。

在该行下方您还可以看到:

Apart from url these are not currently exposed on the EventSource object.

这意味着当前无法从 JavaScript 设置此值。

尽管可以通过在 SSE 消息的 retry 字段中定义它来从您的服务器设置该值。在这里您可以以毫秒为单位定义用户代理在重新连接到您的服务器之前应该等待多长时间。如果你想将它设置为一秒,它应该是:

$time = date('r');
// If the connection closes, retry in 1 second
echo "retry: 1000\n";
echo "data: The server time is: {$time}\n\n";
flush();

当然,如果在第一条消息后不关闭连接,正确实施 SSE 会更好。

A good explanation can be found on MDN. I recommend to use MDN over W3Schools in general. W3Schools is not the most liked resource here on Stack Overflow 这是一个很好的例子。