【问题标题】:Why doesn't server-side script stop when EventSource is closed?为什么 EventSource 关闭时服务器端脚本不停止?
【发布时间】:2020-07-31 02:20:53
【问题描述】:

TL;DR 更新: 无论是从客户端关闭 EventSource 还是完全关闭客户端,php 都会继续在后端执行,并且无法报告 connection_aborted() 的正确值。为什么会这样?

我一直在 Google 和 Stack Overflow 上寻找答案,但没有一个建议的修复程序可以解决这个问题:我有一个简单的页面,使用 JavaScript 和 php 测试服务器发送事件的功能。一切都运行良好,直到我意识到当客户端导航到另一个页面或刷新自身时服务器脚本执行并没有停止。这似乎是一个常见问题,其他问题中给出的建议对我没有任何结果。

我已经调查过的 StackOverflow 问题

我已经调查过的链接文章和其他材料

我已经删除了所有我认为可能是罪魁祸首的代码,但我仍然遇到问题。我特别惊讶connection_aborted 在客户端显式调用EventSource.close() 之后继续报告false,或者只是在10 秒服务器循环完成之前关闭客户端。这是我的确切代码,除了服务器发送的事件之外的所有内容:

sse_tests.js

document.addEventListener('DOMContentLoaded', () => {
  // Set up EventSource for receiving server-sent events.
  const testEventSource = new EventSource('sse_tests.php');
  testEventSource.addEventListener('test', (e) => {
    const data = JSON.parse(e.data);
    console.log(`count: ${data.count}`);
    if (data.count >= 5) {
      testEventSource.close();
    }
  });
});

sse_tests.php

<?php
// Set the event stream header(s).
header("Cache-Control: no-cache");
header("Content-Type: text/event-stream");

// XXX Override automatic detection of client abortion; we'll do it ourselves.
// (This was suggested in another answer, and I have the same issue with or without it)
ignore_user_abort(true);

// Initialize an arbitrary count parameter to investigate client communication.
$count = 1;

while ($count <= 10) {
  $eventData = json_encode(array(
    "count" => $count,
  ));

  echo "event: test\n";
  echo "data: ${eventData}";
  echo "\n\n";

  ob_flush();
  flush();

  $aborted = connection_aborted();

  error_log("count: ${count}, connection_aborted: ${aborted}");

  if ($aborted) {
    break;
  }

  $count++;

  sleep(1);
}

客户端成功打开连接,跟踪它 5 次 test 事件的发射,然后停止看到任何进一步的 test 事件发射,但服务器继续执行完整计数 10,即使在之后testEventSource.close() 调用或在完整计数 10 之前关闭浏览器窗口,此处的服务器日志内容证明了这一点:

count: 1, connection_aborted: 0
count: 2, connection_aborted: 0
count: 3, connection_aborted: 0
count: 4, connection_aborted: 0
count: 5, connection_aborted: 0
count: 6, connection_aborted: 0
count: 7, connection_aborted: 0
count: 8, connection_aborted: 0
count: 9, connection_aborted: 0
count: 10, connection_aborted: 0

我正在使用 php 7.2 共享主机,并且对服务器配置进行了最小的调整。如果这可能是冲突的根源,请告诉我,我将尝试调查更多默认配置并分享其他需要的内容。

【问题讨论】:

  • connection_status()的值是多少?
  • @miknik 状态为 0(正常)
  • 在你的 php.ini 中有这两行吗? output_buffering = 0 implicit_flush = 1
  • 听起来您在某处进行了一些输出缓冲。我刚刚将您的代码复制到了我的服务器上,它运行良好。
  • 正确,网页上的控制台日志会以预期的时间间隔更新每个计数。

标签: javascript php server-sent-events eventsource


【解决方案1】:

根据更新的信息,我认为这肯定是错误的:

ignore_user_abort(true);

这应该是:

ignore_user_abort(false);

... 这样断开连接就不会被忽略。之后发生的事情是个谜。 MDN 报告该连接是持久的,因此可能是浏览器中的一个错误没有关闭连接。如果存在负载平衡器或反向代理,则可能是它们的问题。这可能是 Web 服务器中的问题。或者它可能是 PHP 配置中的问题。

在聊天中,测试服务器很可能是在 FastCGI 下运行 PHP 的 nginx。您是否正在使用带有 mod_php 的 Apache?如果是这样,当您将 PHP 作为 CGI 运行时还会发生这种情况吗?这应该有助于进一步隔离问题。

我也会使用 connection_status() 以便您可以更加确定连接状态。 https://www.php.net/manual/en/features.connection-handling.php

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-14
    • 1970-01-01
    • 2013-04-04
    • 1970-01-01
    • 1970-01-01
    • 2018-10-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多