javascriptphpcurlserver-sent-events

SSE (server side event) went CSE (Client Server Event) - loop sse.php working only with curl


Around 2017 I wrote a SSE (PHP) script and the JavaScript code. It worked fine with PHP-5 + HTTP/1 and the Firefox of that era.

The same code now does not work with Firefox-140 esr or latest Chrome with PHP-8.2 + HTTP/2. I have a time-out after 60 seconds.

Also tried the simplest SSE example from lucidar.me, zip. If I remove the while loop something that I think it's bad, it's working. In that case the JavaScript makes requests every 5 seconds. I think this defeats the purpose of SSE.

The code with while works fine with curl but not with browsers.

My implementation and the rationale of SSE is that the server decides when to send the data, not the client. Right?

It changed something in JavaScript I guess, in browsers, or did I miss something? It's the HTTP/2 the problem?

The code works with curl like that (while version)

<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache, no-transform');
header('X-Accel-Buffering: no');
header('Access-Control-Allow-Origin: *');
set_time_limit(0);
@ini_set('zlib.output_compression', 0);
@ob_implicit_flush(true);

// Loop until the client close the stream
while (true) {

  // Echo time
  $time = date('r');
  echo "data: The server time is: {$time}\n\n";
 
  // Flush buffer (force sending data to client)
  @ob_flush();
  flush();

  // Wait 2 seconds for the next message / event
  sleep(2);
}
?>

Added info after @Hybrid gave me an idea.

Forgot to mention that I use apache. I switched to HTTP/1 and the result is bizarre. curl now responds after 2 minutes. With HTTP/2 the response was instant. Now Firefox responds like curl.

Testing with HTTP/1 only server

export LC_ALL=C; date; curl https://XXX/sse.php
Fri Jul 25 23:17:48 EEST 2025 <-- date invoked
data: The server time is: Sat, 26 Jul 2025 00:19:18 +0300 <-- received after 1 minute and 30 seconds.

data: The server time is: Sat, 26 Jul 2025 00:19:20 +0300

data: The server time is: Sat, 26 Jul 2025 00:19:22 +0300

... total 58 lines of data: received.

Here testing with HTTP/2 again. Only curl works, not browsers.

curl -v URL by-default uses HTTP/2:

* ALPN: curl offers h2,http/1.1
* ALPN: server accepted h2

So browsers, can't handle SSE with HTTP/2?


Solution

  • It helps if you get sleep :) The solution was to disable buffering but since I use php-fpm with apache mod_proxy_fcgi I cannot disable output buffering script wise (maybe I am wrong here?).

    So one solution is for apache conf is here: stackoverflow link

    Flush packets every 10ms.

    # max=10 = 10ms
    <Proxy "fcgi://localhost/" enablereuse=on flushpackets=on max=10>
    </Proxy>
    

    I don't know the implications of that. But for SSE it works both for http:// and https://.

    So maybe a better solution is here

    echo 'SetEnv no-gzip 1' > .htaccess
    

    Problem is that works only with https:// not with http://

    It seems that those in .php script are useless

    @ini_set('zlib.output_compression', 0);
    @ini_set('output_buffering', 'off');
    
    

    because they run AFTER apache?

    Now it works with HTTP/2 and HTTP/1.

    Thanks @hybrid for the inspiration.