服务器发送的事件可以工作,但有大量的时间延迟


Server sent events work, but with a massive time delay

我首先会说这在我的本地机器上非常有效,下面的js示例连接到stream.php,并每秒接收服务器的持续更新。

index.php

var source = new EventSource("stream.php");
source.addEventListener('message', function(e) {
    console.log(e);
}, false);
source.addEventListener('open', function(e) {
    console.log(e);
}, false);
source.addEventListener('error', function(e) {
    if (e.readyState == EventSource.CLOSED) {
        console.log('closed');
    }
}, false);

stream.php

while(true)
{
    // Headers must be processed line by line.
    header('Content-Type: text/event-stream');
    header('Cache-Control: no-cache');
    // Set data line
    print "data: " . date( 'G:H:s', time() ) . PHP_EOL . PHP_EOL;
    // Toilet
    flush();
    // Wait one second.
    sleep(1);
}

我确实预计上传到实时dev.服务器后会有一点延迟。但在我看到第一个条目之前,还有大约15到20分钟的时间延迟。

连接未断开。(问题已经持续了40分钟以上。)这只是Apache循环问题(意味着是时候查看web套接字了)还是我可以做些什么来解决这个问题?

Server.php需要如下所示:

stream.php

while(true)
{
    // Headers must be processed line by line.
    header('Content-Type: text/event-stream');
    header('Cache-Control: no-cache');
    // Set data line
    print "Event: server-time" . PHP_EOL;
    print "data: " . date( 'G:H:s', time() ) . PHP_EOL;
    print PHP_EOL;
    ob_end_flush();     // Strange behaviour, will not work
    flush();            // Unless both are called !
    // Wait one second.
    sleep(1);
}

@Derrick,你建议的ob_end_flush();行让我很接近,但在比hello世界代码更复杂的PHP中,我的SSE连接仍然会被不必要的重新打开(我仍然不完全理解ob_end_flush()为什么要这样对我)。以下是我现在使用的模式(在其他方面与您的stream.php相同)。在英语中,我在进入无限循环之前关闭php输出缓冲:

// per http://www.php.net/manual/en/book.outcontrol.php:
//     Clean (erase) the output buffer and turn off output buffering
ob_end_clean();
// how long PHP script stays running/SSE connection stays open (seconds)
set_time_limit(60);
while (true) {
  // use @Derrick's header/send code here
  ob_flush();  // note I don't turn off output buffering here again
  flush();
  sleep(1);
}

睡眠正在阻塞SSE。我也有同样的问题。有人建议我使用事件驱动编程。

只需添加,ob_flush();stream.php 中flush()函数之前

更新后的stream.php脚本如下,在flush()函数之前观察ob_flush()函数。

while(true)
{
    // Headers must be processed line by line.
    header('Content-Type: text/event-stream');
    header('Cache-Control: no-cache');
    // Set data line
    print "data: " . date( 'G:H:s', time() ) . PHP_EOL . PHP_EOL;
    // Toilet
    **ob_flush();**
    flush();
    // Wait one second.
    sleep(1);
}

您可以通过回波重试设置延迟,例如


header('Content-Type: text/event-stream');
header('Cache-Control: no-cache'); //to prevent caching of event data
header('Access-Control-Allow-Origin: *'); //allows stream access from current domain only
$time = date('h:i:s');
$id = time(); //to set id with current timestamp
echo "data:$time'n";
echo "retry:2000'n";  //2 seconds
echo "id=$id 'n'n";
ob_flush();
flush();