I'm trying to use server sent events so my webpage can have periodic time updates from my server. The issue is that my client is able to interact with my server, however, the response from my server is not making it to my client? Basically, when I open my html file with firefox I know my server gets the request and then it starts sending responses, but nothing shows up on my webpage... Not quite sure what's the issue. Help appreciated!
Here is my client code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<script>
function init(){
if(typeof(EventSource)!=="undefined"){
var source = new EventSource('localhost');
source.onmessage = function(e) {
document.body.innerHTML += e.data + '<br>';
};
}
else{
document.body.innerHTML = "Sorry, your browser does not support server-sent events...";
}
}
</script>
<body onload="init()">
</body>
</html>
Here is my server code (node.js):
var http = require('http');
var sys = require('sys');
var fs = require('fs');
http.createServer(function(req, res) {
if (req.headers.accept && req.headers.accept == 'text/event-stream') {
sendSSE(req, res);
}).listen(80, "127.0.0.1");
function sendSSE(req, res) {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
var id = (new Date()).toLocaleTimeString();
// Sends a SSE every 5 seconds on a single connection.
setInterval(function() {
constructSSE(res, id, (new Date()).toLocaleTimeString());
}, 5000);
}
function constructSSE(res, id, data) {
res.write('id: ' + id + '\n');
res.write("data: " + data + '\n\n');
}
You need to add in
res.end();
somewhere and remove the 'setInterval'. It looks like what you're trying to do, however, is keep the connection alive, in which case you need to change your code significantly. Look into the 'net' module, which is more designed for a "constant on" interactive type of connection.
http://nodejs.org/api/net.html#net_net
The http module is designed for finite, exchange of data, type of requests. You're trying to make it do something it isn't designed to do.
/*jshint node:true */
var http = require('http');
http.createServer(function (req, res) {
'use strict';
console.log('GOOD request recieved');
res.write('hi there');
res.end();
console.log('GOOD end sent');
}).listen(8888);
http.createServer(function (req, res) {
'use strict';
console.log('BAD request received');
res.write('hi there');
console.log('BAD response wrote not ending');
}).listen(8889);
Consider the two servers I have above. If you ping them both with node client code, you will see data come in to both, and should see chunks as they are sent. However, if you try to ping 8889 with a browser, the webpage will never render, because the end event is never sent. Browsers depend on this to know all content has been received. If you're client code is working within a browswer, this may be effecting things. Attempt to use plain NodeJS client code against your server first, and make sure data is getting sent the way you expect it is. Then work on figuring out how the browser is upsetting things. My guess would be that the data gets received by the browser, but it never does anything with it, and sits and waits to distribute it for that 'end' event, the same way in which the 8889 server's webpage never renders... it believes there is more data to wait for.
Sample client code:
var options = {
hostname: '127.0.0.1',
method: 'GET'
};
options.port = 8888;
http.request(options, function (res) {
'use strict';
console.log('GOOD Pinged server');
res.on('data', function (chunk) {
console.log('GOOD data chunk:' + chunk);
});
res.on('end', function () {
console.log('GOOD end event recieved');
});
}).end();
options.port = 8889;
http.request(options, function (res) {
'use strict';
console.log('BAD Pinged server');
res.on('data', function (chunk) {
console.log('BAD data chunk:' + chunk);
});
res.on('end', function () {
console.log('BAD end event recieved');
});
}).end();
The http module in node works fine for Server Sent Events and most demo code for Node SSE uses it. But you do have to be careful about some gotchas.
I got bit by compression being turned on. The solution there is to add res.flush() after the last res.write() of each data message. Since that's an easy fix, I would try that first before rewriting using a different module.