javascript - 如果没有发送任何内容,为什么我在服务器上的 php SSE 文件在浏览器关闭时继续工作?

标签 javascript php server-sent-events

我对 SSE 有一种奇怪的行为。

我有 2 个文件,一个用于服务器端,一个用于浏览器客户端。

serverside.php 是这样的:

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

  while( true ) {
    set_time_limit(30);

    $time = date('d/m/Y H:i:s');

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

    error_log('i am here!');
    sleep(1);
   }
?>

客户端文件是这样的:

<!DOCTYPE html>
<html>
<body>

<div id="result"></div>
<script>
    var source;

    if(typeof(EventSource) === "undefined") {
      alert('Problem with your browser.');
    }

    source = new EventSource("serverside.php");
    source.onopen = function (event) {
      console.log('streaming SSE opened');
    };

    source.onmessage = function(event) {
      console.log('Streaming Message Received');
      document.getElementById("result").innerHTML = event.data;
    };

    source.onerror = function (event) {
    console.log('ERROR EventSource');
  }
</script>

</body>
</html>

如果我测试这一切运行正常。我在浏览器中获得了刷新时间,当我关闭浏览器中的选项卡时,serverside.php 不会发送更多“我在这里!”要记录的消息。这是正确的行为。当浏览器选项卡关闭时,serverside.php 必须停止。

但是现在,如果我在 serverside.php 文件中删除或注释这些行:

// echo 'data: ' . $time . "\n\n";
// flush();

serverside.php 文件仍然是这样的:

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

  while( true ) {
    set_time_limit(30);

    $time = date('d/m/Y H:i:s');

     //  echo 'data: ' . $time . "\n\n";
     //  flush();

    error_log('i am here!');
    sleep(1);
   }
?>

也就是说,根本没有刷新数据。

如果我现在加载 index.php,我将不会从 serverside.php 收到任何信息。 但在这种情况下,当我关闭浏览器选项卡时,serverside.php 继续工作并发送记录“我在这里”消息。

此外,如果 serverside.php 发送数据,并且在一些消息发送后停止发送更多数据,行为是相同的。 “我在这里”消息在选项卡关闭后继续到达。

  • 如果我在从 serverside.php 发送数据时关闭浏览器选项卡,一切正常。
  • 如果我在发送数据后关闭浏览器选项卡并且没有从 serverside.php 发送任何内容,serverside.php 将继续工作。

这是什么解释?

我完全卡住了。

最佳答案

(我假设 Apache 是服务器,而您使用的是 mod_php,但基本思想应该与任何 Web 服务器相同。)

如果您的 PHP 脚本从不执行 flush(),Apache 缓冲区内容只会在缓冲区变满时发送到客户端(您的浏览器)。这永远不会发生,因为您的脚本永远不会执行 echo

Apache 意识到客户端已断开连接的方式是尝试在套接字上向其发送一些内容并收到错误。这永远不会发生,因为你从不发送任何东西! (是的,要意识到 TCP/IP 套接字不再工作,您必须尝试使用​​它并失败;没有您可以查看的简单状态。)

我知道最好的解决方案是让服务器端脚本发送一条保持事件消息。 IE。每(例如)40 秒显示一条空白消息或时间戳。如果您真正的数据流已经安静下来,但您每 40 秒发送一次保持事件状态,那么您注意到客户端已断开连接的平均时间将为 20 秒。

(这绝对是个好主意,尤其是当客户端频繁连接和断开连接时,否则它们会有效地保持套接字和 Apache 进程处于打开状态。)

关于javascript - 如果没有发送任何内容,为什么我在服务器上的 php SSE 文件在浏览器关闭时继续工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56472944/

相关文章:

javascript - WordPress的function.php wp_enqueue_script不工作

java - 在 tomcat servlet 上使用服务器发送事件进行 gzip/deflate 压缩

javascript - 多个 $http 的 Angular promise

javascript - 是否有使用 Chrome 调试协议(protocol)/API 的浏览器库?

php - 将一个表中的数据和一些硬代码插入到另一个表中

php - 如果我的数组索引相同,如何使用 foreach 获取表数据

websocket - 现在,Comet是否已被服务器发送的事件和WebSocket淘汰了?

ruby - 在 Sinatra 应用程序中处理事件流连接

javascript - 找不到与 Mozilla Ghostwriter 演示相关的图像

javascript - 您可以在不使用表单的情况下将数组从 javascript 传递到 asp.net mvc Controller 操作吗?