On my Express/Node server, I set the content type to text/event-stream
:
res.writeHead(200, {
'Content-Type': 'text/event-stream'
});
Then, as a series of callbacks fire, I write data messages to the stream and follow it with two new lines:
res.write('data: ' + JSON.stringify(data) + '\n\n');
If I add logging on the server side or if I just hit the URL with curl
, I can see that data messages are being written over a few seconds.
However, when I try to use these data messages in a web page, nothing happens. (I'm testing on Chrome, Firefox, and Safari all on a Mac.) Here's what the Web page looks like:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Testing</title>
</head>
<body>
<h1>Server-Sent Events Test</h1>
<script>
var source = new EventSource('/library/search?q=medicine&async');
source.onmessage = function(e) {
document.body.innerHTML += JSON.parse(e.data).name + '<br>';
};
</script>
</body>
</html>
If I add a final callback on the server side that closes the connection (using res.end()
) then the browsers respond to the data messages all at once, and only once res.end()
has happened. Which would seem to defeat the purpose of using Server-Sent Events.
What do I need to change (short of giving up and switching to XHR polling) to have the browsers respond to the Server-Sent Events as they arrive (which would seem to be exactly the purpose and use case for Server-Sent Events)?
(Test page demonstrating the problem was available but now that this problem has been resolved, I've removed it.)
Check Browser Support for SSE: Before implementing the SSE, checking the support of the browser is necessary. To check the support, we'll use an if and else statement and run the following code using the EventSource object. The EventSource object is used to receive the events or notifications from the server.
To use Server-Sent Events in a web application, you would need to add an <eventsource> element to the document. The src attribute of <eventsource> element should point to an URL which should provide a persistent HTTP connection that sends a data stream containing the events.
A connection over Server-Sent Events typically begins with client-initiated communication between client and server. The client creates a new JavaScript EventSource object, passing the URL of an endpoint to the server over a regular HTTP request. The client expects a response with a stream of event messages over time.
It looks like you have some middleware that is doing compression; and in doing this, it is buffering until you complete the response. You can see this with curl:
First, bare GET:
curl <url>
Next, add an Accept-Encoding
header (similar to what your browser is using):
curl <url> -H 'Accept-Encoding: gzip,deflate,sdch' --compressed
Note that --compressed
just tells curl
to decompress it for you.
You'll notice that you see the expected behavior on the first one, but not the second. This makes it clear that it is related to the compression. I suggest turning off compression for that route, or finding a smarter middleware that knows how to compress each frame.
It works fine for me in Chrome. Here's my test code:
sse.js:
var app = require('express')();
app.get('/', function(req, res) {
res.sendFile(__dirname + '/sse.htm');
});
app.get('/events', function(req, res) {
var counter = 0;
res.writeHead(200, { 'Content-Type': 'text/event-stream' });
setInterval(function() {
res.write('data: ' + JSON.stringify({name: 'foo' + (counter++) }) + '\n\n');
}, 1000);
res.write('data: ' + JSON.stringify({name: 'foo' + (counter++) }) + '\n\n');
});
app.listen(8000);
sse.htm:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<h1>Server-Sent Events Test</h1>
<script>
var source = new EventSource('/events');
source.onmessage = function(e) {
document.body.innerHTML += JSON.parse(e.data).name + '<br />';
};
source.onerror = function(e) {
source.close();
};
</script>
</body>
</html>
this produces the following output:
foo0 // one second later foo1 // two seconds later foo2 // three seconds later foo3 // etc.
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