PHP服务器推送事件连接无法关闭?

5

我已经在我的网络应用程序中使用 服务器发送事件事件源 进行了实现。基本上,我的JavaScript代码如下:

    var myEventSource;
    if (typeof(EventSource) !== "undefined" && !myJsIssetFunction(viridem.serverSideEvent.config.reindexProcessingEvent)) {
        myEventSource = new EventSource('/my/url/path.php?event=myevent');
        EventSource.onmessage = function(e) {
          [...] //Dealing with e.data that i received ...
        }
    }

在PHP端,我有类似这样的内容:
<?php
  header('Content-Type: text/event-stream');
  header('Cache-Control: no-cache');
  header("Access-Control-Allow-Origin: *");

  //this or set_the_limit don't work but whatever I can deal without it
  ini_set('max_execution_time', 300);
  //ignore_user_abort(true); tried with true and false

  bool $mustQuit = false;

  while (!$mustQuit && connection_status() == CONNECTION_NORMAL) {
     if(connection_aborted()){
      exit();
     }
     [...] //doing some checkup

    if ($hasChange) {
      //Output stuffs
      echo 'data:';
      echo json_encode($result);
      echo "\n\n";
      ob_flush();
      flush();
      sleep(5);
    }

  }

根据在PHP Event Source keeps executing找到的答案,"text/event-stream"头应该会自动关闭连接,但在我的情况下没有关闭。

我在window.onbeforeunload事件中添加了eventsource.close,但它没有关闭事件。

window.onbeforeunload =  function() {
    myEventSource.close();
    myEventSource = null;
};

如果我查看浏览器的网络部分,我可以看到头文件是(在添加最大循环30后): Content-Type: text/event-stream;charset=UTF-8
响应头:
Access-Control-Allow-Origin: * Cache-Control: no-cache Connection: Keep-Alive Content-Type: text/event-stream;charset=UTF-8 Server: Apache/2.4.18 (Ubuntu) Date: Thu, 26 Apr 2018 20:29:46 GMT Expires: Thu, 19 Nov 1981 08:52:00 GMT
请求头:
Connection: keep-alive Accept: text/event-stream Cache-Control: no-cache 注意:我确认脚本仍在运行,通过日志和检查Apache2进程与bash(ps -ax | grep -c apache2)始终增加。

只需执行以下代码 `while (true) {if (connection_aborted()) { exit();` 我使用这个已经有一段时间了,可以很好地杀死进程。例如:https://dev59.com/9Knka4cB1Zd3GeqPPH8X#49081040 - Lawrence Cherone
connection_aborted() 总是返回 int(0) :/ - Jordan Daigle
我最终使用最大循环次数而不是max执行时间和set_time_limit,因为这样无法停止脚本的连续运行。我想我会将它们设置为无限执行时间或将它们删除。 - Jordan Daigle
2
这个想法是让它持续运行,只有在客户端断开连接时才退出。你可以在循环内部放置一个检查,以防止像 https://github.com/lcherone/sse-chat-example/blob/master/sse.php#L89 这样的过度运行,但在大多数情况下不需要它,因为 connection_aborted 可以正常工作。 - Lawrence Cherone
这个回答解决了你的问题吗?PHP事件源持续执行 - pato
显示剩余3条评论
1个回答

5
感谢@LawrenceCherone的帮助,我发现你需要“输出数据”才能使connection_aborted起作用...
在我的情况下,我只在需要时输出数据...
通过添加
   if ($hasChange) {
      //Output stuffs
      echo 'data:';
      echo json_encode($result);
      echo "\n\n";
      ob_flush();
      flush();
      sleep(5);

    } else {
       echo 'data:';
       echo "\n\n";
       ob_flush();
       flush();
       if(connection_aborted()){
         exit();
       }
       sleep(5);
    }

connection_aborted 开始工作。


你只需要确保定期发送保持连接消息。通常不超过40秒。这将确保 connection_aborted() 最多延迟40秒。 - asiby
1
不要发送空数据,最好发送一个注释,即以分号开头的任何字符串,例如 echo“:ping \n \n” - pato
乔丹,你救了我的一天,谢谢。 - Stefano
这将不断向客户端发送数据。而服务器推送事件是为了减少负载而设计的。 - Avatar
@Avatar connection_aborted和connection_status只返回服务器知道的内容。此时,eventsource.close()或关闭浏览器并没有通知Apache连接已中止。还有可能是某人失去了互联网连接,因此无法通知服务器,因此仍需要检查连接并向客户端发送数据。据我所知,应该有较低的HTTP开销(https://dev59.com/Emox5IYBdhLWcg3wJxL4#9544887)在我的情况下,我们现在使用websocket以实现多功能性并避免并发连接。 - Jordan Daigle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接