SSE 不会使用ignore_user_abort() 和connection_aborted() 断开连接

问题描述 投票:0回答:1

我从 W3 Schools 中获取了一个 SSE 示例,并注意到使用

Dev Tools
它不断创建新连接。查看 Kevin Choppin 的博客,我修改了
W3 Schools
示例以使用
while(true)
以及
ignore_user_abort()
connection_aborted()
。使用
Dev Tools
我现在可以看到一个持久连接,但是当我关闭选项卡或关闭浏览器时,我没有看到 `connection_aborted()' 返回 true。

上交所代码:

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

ignore_user_abort(true);
while (true) {
  if (connection_aborted()) {
    file_put_contents("/tmp/test", "help");
    exit();
  }

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

  sleep(1);
}
?>

请注意,如果我将

file_put_contents()
移至
connection_aborted()
检查上方,则文件将成功写入。所以这不是权限问题。

我注意到有一个

connection_status()
功能。所以我修改了代码以使用 switch case 来显示状态。

上交所代码:

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

ignore_user_abort(true);
while (true) {
    switch (connection_status()) {
      case CONNECTION_ABORTED:
        file_put_contents("/tmp/test", "CONNECTION_ABORTED");
        break;
      case CONNECTION_NORMAL:
        file_put_contents("/tmp/test", "CONNECTION_NORMAL");
        break;
      case CONNECTION_TIMEOUT:
        file_put_contents("/tmp/test", "CONNECTION_TIMEOUT");
        break;
      case __COMPILER_HALT_OFFSET__:
        file_put_contents("/tmp/test", "__COMPILER_HALT_OFFSET__");
        break;
      default:
        break;
    }

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

  sleep(1);
}
?>

使用此代码,文件会不断被写入,并且我收到

CONNECTION_NORMAL
作为我的输出。

ls -l /tmp/test ; cat /tmp/test
-rw-r--r-- 1 <user> <user> 17 Jan 18 11:09 /tmp/test
CONNECTION_NORMAL

连接没有中止,我很难找出原因。我在浏览器中使用

Microsoft Edge
,但也尝试了
Chrome
Firefox
。我还完全关闭了浏览器并使用
Task Manager
来终止该进程。已经过去 20 分钟了,时间戳仍在更新
CONNECTION_NORMAL

至于在浏览器中运行的客户端代码,与

W3 Schools
示例相同。

<!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>

关于后端,服务器正在运行

apache

看到@JS_Riddler 的这个答案后获得更多信息。我对此的理解是,如果输出被缓冲,即使使用flush(),PHP也可能不会中止连接。我添加了带有

ob_get_contents()
ob_end_clean()
的 while 循环,但没有成功。此外,我还复制了
DestructTester
类的确切示例,无论
ignore_user_abort()
是否设置为
true
,输出都是相同的。每张照片都是
NO

上交所代码:

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

ignore_user_abort(true);
while (true) {
    switch (connection_status()) {
      case CONNECTION_ABORTED:
        file_put_contents("/tmp/test", "CONNECTION_ABORTED");
        break;
      case CONNECTION_NORMAL:
        file_put_contents("/tmp/test", "CONNECTION_NORMAL");
        break;
      case CONNECTION_TIMEOUT:
        file_put_contents("/tmp/test", "CONNECTION_TIMEOUT");
        break;
      case __COMPILER_HALT_OFFSET__:
        file_put_contents("/tmp/test", "__COMPILER_HALT_OFFSET__");
        break;
      default:
        break;
    }

  $time = date('r');
  echo "data: The server time is: {$time}\n\n";
  while (ob_get_level()){
    ob_get_contents();
    ob_end_clean();
  }
  flush();

  sleep(1);
}
?>

另一个更新。如果在客户端我使用

source.close();
它仍然没有检测到连接中止。我还尝试将
output_buffering
中的
php.ini
设置为 0,但没有成功。这感觉很破碎。

javascript php server-sent-events
1个回答
0
投票

根据我自己实施类似事情时的记忆以及这个问题,您需要添加

ob_flush()
flush()
。老实说,我不确定为什么这有效,但它确实对我有效,并且显然也对其他用户有效。

© www.soinside.com 2019 - 2024. All rights reserved.