SSE (server-sent events)

Problems with the Windows version of XAMPP, questions, comments, and anything related.

SSE (server-sent events)

Postby lucky4udanny » 26. July 2023 13:10

I have two dev environments using XAMPP. One is MacOS and the other is Windows 11. In both cases, SSE doesn't work as expected.

If the php runs in a loop with sleep(5) and sends messages to the client each 5 second iteration, the client receives the messages properly. However it presents an error when the loop ends and the connection is closed:
test.html:22 Error occurred: Event {isTrusted: true, type: 'error', target: EventSource, currentTarget: EventSource, eventPhase: 2, …}

I could ignore the error since at that point I am done with the server-sent events. However, when I have the server doing a long process and send messages to the client as certain chunks of processing are completed, it seems like the connection is dropped within 2 seconds and it attempts to reconnect. None of the messages are received at the client end. I see no errors anywhere. (server logs, xdebug step through, dev-tools step-through, console on client side)

What am I missing? Is there a server requirement that XAMPP default install does not include?

html/js
Code: Select all
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
    <script>
        function initializeSSE()
        {
            var eventSource = new EventSource('test.php');

            eventSource.onopen = function(event)
            {
                console.log('Connection opened:', event);
            }
            eventSource.onmessage = function(event)
            {
                console.log('Message received:', event.data);
            }
            eventSource.onerror = function(event)
            {
                console.error('Error occurred:', event);
                eventSource.close();
            };
            eventSource.onclose = function(event)
            {
                console.log('Connection closed:', event);
                // Attempt to reopen the connection after a short delay (e.g., 5 seconds)
                setTimeout(initializeSSE, 5000);
            };
        }

        initializeSSE();
      </script>
</body>
</html>



PHP
Code: Select all
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);

header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');

function sendSSE($data) {
    echo "data: $data\n\n";
    ob_flush();
    flush();
}

$interval = 5;
$i = 3;
while ($i > 0) {
    sleep($interval);
    sendSSE($i);
    $i--;
}

echo "event: close\ndata:\n\n";
@ob_flush();
flush();
?>
lucky4udanny
 
Posts: 2
Joined: 26. July 2023 12:22
XAMPP version: 3.3.0
Operating System: Windows 11

Re: SSE (server-sent events)

Postby lucky4udanny » 27. July 2023 03:10

I will answer my own question. I misunderstood how the SSE was intended to work.

The client (JS) initiates SSE AND closes SSE. The server can't initiate or close it SSE. I was trying to have server-side PHP end the SSE connection.
eventSource = new EventSource("/path/to/stream-url"); // JS opens the SSE connection.
eventSource.close(); // JS closes the SSE connection.

Since the server can't close the connection, it NEEDS to run an ENDLESS LOOP when SSE is opened. Otherwise, the client sees the connection was dropped and tries to reconnect every 2 seconds or so. This was what I was experiencing.

I changed the php script to include an endless loop at the very end of a sequence of processes. The PHP completes tasks one at a time, sending an occasional message to the client indicating progress. When all the tasks are complete, it enters the endless loop where it sends a request for the client to close the connection each iteration and waits for the client to comply.

On the client side, JS examines each message, and when the message matches a close request, JS client closes it (eventSource.close();).

I have tested this, and it works perfectly.

Javascript in browser:
Code: Select all

    const url = `sse.php?${params}`;
    var eventSource = new EventSource(url);

    eventSource.onmessage = function(event) {
        updateStatus(event.data);
        if(event.data == 'close')
        {
           eventSource.close();
         }
    };



PHP on server:
Code: Select all
<?php

   require_once 'assets/includes/dbhandler.inc.php';

   header('Content-Type: text/event-stream');
   header('Cache-Control: no-cache');
   header('Connection: keep-alive');
   header("Access-Control-Allow-Origin: *");

   // Helper function to send messages to the client
   function sendEvent($message) {
       echo "data: " . $message . "\n\n";
       ob_flush();
       flush();
   }

   sendEvent("Working on task 1...");
   // task 1
   sendEvent("Working on task 2...");
   // task 2
   sendEvent("Working on task 3...");
   // task 3
   ...

   while (true)
   {
      sleep(3);
      sendEvent("close");
      $i++;
   }
?>
lucky4udanny
 
Posts: 2
Joined: 26. July 2023 12:22
XAMPP version: 3.3.0
Operating System: Windows 11


Return to XAMPP for Windows

Who is online

Users browsing this forum: No registered users and 166 guests