I am new to server-sent events, so I am trying this W3Schools example on WAMP Server. The files I have are:
demo_sse.php
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
$time = date('r');
echo "data: The server time is: {$time}\n\n";
flush();
?>
index.php
<!DOCTYPE html>
<html>
<body>
<h1>Getting server updates</h1>
<div id="result"></div>
<script>
if(typeof(EventSource) !== "undefined") {
var source = new EventSource("demo_sse.php");
source.onmessage = function(event) {
document.getElementById("result").innerHTML += event.data + "<br>";
};
} else {
document.getElementById("result").innerHTML = "Sorry, your browser does not support server-sent events...";
}
</script>
</body>
</html>
As far as I understand, time is constantly changing, so the updates must be sent every second (at least). However, the updates are received every three seconds. This interval was not specified in demo_sse.php, so:
So what are Server-Sent Events? A client subscribes to a “stream” from a server and the server will send messages (“event-stream”) to the client until the server or the client closes the stream. It is up to the server to decide when and what to send the client, for instance, as soon as data changes.
They are commonly used to send message updates or continuous data streams to a browser client and designed to enhance native, cross-browser streaming through a JavaScript API called EventSource, through which a client requests a particular URL in order to receive an event stream.
What are Server-Sent Events? SSE definition states that it is an http standard that allows a web application to handle a unidirectional event stream and receive updates whenever the server emits data. In simple terms, it is a mechanism for unidirectional event streaming.
The example on W3Schools is a bit of a bad example.
For most HTTP response/requests exchanges, the client makes an HTTP request to the server, the server sends back data and the exchange is complete.
For SSE (although it still uses the HTTP protocol) this works a bit different. Here the client makes a request to the server, the session remains open and the server can send data whenever it pleases. If the session is closed for whatever reason, the EventSource will try to reconnect and everything starts over.
The problem in your PHP script is that the script ends the request/response exchange after it finished the last line. This means that the connection is closed and so the EventSource
will try to reconnect. (Adding an .onerror
event will show that an error is raised after every message.)
As is defined in the specification:
A reconnection time, in milliseconds. This must initially be a user-agent-defined value, probably in the region of a few seconds.
This is why you receive updates every three seconds. Because that is what the user-agent-defined value is set to.
Just below that line you can also see:
Apart from url these are not currently exposed on the EventSource object.
This means that this value cannot currently be set from JavaScript.
It is possible though to set this value from your server by defining it in the retry
field in the SSE message. Here you can define in miliseconds how long the user agent should wait before reconnecting to your server. If you want to set it to one second it should be:
$time = date('r');
// If the connection closes, retry in 1 second
echo "retry: 1000\n";
echo "data: The server time is: {$time}\n\n";
flush();
But of course it would be better to implement SSE properly without closing the connection after the first message.
A good explanation can be found on MDN. I recommend to use MDN over W3Schools in general. W3Schools is not the most liked resource here on Stack Overflow and this is a good example why.
According to this article on the late, great HTML5 Rocks:
The magical part is that whenever the connection is closed, the browser will automatically reconnect to the source after ~3 seconds. Your server implementation can even have control over this reconnection timeout. See Controlling the reconnection-timeout in the next section.
The demo_sse.php
ends after the flush
, so the connection is closed; the browser is automatically reconnecting in 3(ish) seconds.
To control the reconnection timeout on the server, you can send a retry
field in the stream. From this MDN doc it can be determined that if you add
echo "retry: 1000\n\n";
line before the echo "data:
line, it will change the timeout to 1 second.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With