问题
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, the 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:
- Why does it send the updates every 3 seconds?
- How do I change this interval?
回答1:
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.
回答2:
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.
来源:https://stackoverflow.com/questions/53888030/why-do-server-sent-events-initiate-every-3-seconds