PHP 服务器发送事件连接不会关闭?

Posted

技术标签:

【中文标题】PHP 服务器发送事件连接不会关闭?【英文标题】:PHP Server Sent Events Connection won't close? 【发布时间】:2018-10-07 15:55:41 【问题描述】:

我在我的 Web 应用程序上实现了 server sent events 和 eventsource。 基本上在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 之后): 内容类型:文本/事件流;charset=UTF-8

响应标头:

访问控制允许来源:*

缓存控制:无缓存

连接:保持活动状态

内容类型:文本/事件流;charset=UTF-8

服务器:Apache/2.4.18 (Ubuntu)

日期:2018 年 4 月 26 日星期四 20:29:46 GMT

到期:格林威治标准时间 1981 年 11 月 19 日星期四 08:52:00

请求标头:

连接:保持活动

接受:文本/事件流

缓存控制:无缓存

注意:我确认脚本仍在使用日志运行,并通过始终递增的 bash (ps -ax | grep -c apache2) 检查 apache2 进程。

【问题讨论】:

就这样做while (true) if (connection_aborted()) exit(); 我已经使用了一段时间并且可以很好地终止进程。例如:***.com/a/49081040/661872 connection_aborted() 总是返回 int(0) :/ 不确定您的测试方式,但您还需要ignore_user_abort(true);你把它关掉了。 你不应该使用 max_execution_time 这个想法是它确实会连续运行,并且只有在客户端断开连接时才会退出。..您可以在循环中放置一个检查,以防止像 github.com/lcherone/sse-chat-example/blob/master/sse.php#L89 这样的过度运行,但它不需要大多数情况下.. 因为 connection_aborted 工作正常。 【参考方案1】:

感谢@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_abordted() 最多延迟 40 秒。 与其发送空数据,不如发送一个以分号开头的任何字符串的注释,例如echo ": ping\n\n"; 乔丹,你拯救了我的一天,谢谢 这会不断地向客户端发送数据。服务器发送的事件是为了减少负载。 @Avatar connection_aborted 和 connection_status 只返回服务器知道的内容。当时 eventsource.close() 或关闭浏览器并没有通知 apache 连接已中止。也有可能有人失去了他的互联网连接,因此无法通知服务器,因此您仍然需要检查连接并将数据发送到客户端。据我所知 (***.com/a/9544887/6126481) 应该有更低的 HTTP 开销。在我的情况下,我们现在使用 websocket 来实现多功能性并避免并发连接。

以上是关于PHP 服务器发送事件连接不会关闭?的主要内容,如果未能解决你的问题,请参考以下文章

Ktor sse 客户端断开连接

对服务器发送的事件感到困惑

HTML5 服务器发送事件原型 - 模棱两可的错误和重复轮询?

通过 Nginx 在 Node.js 上的服务器发送事件连接超时

Spring boot:SSE 服务器发送的事件不起作用

来自 php 服务器的推送通知不会发送到 ios