I'm writing a simple node.js server with socket.io implementation. When I go to mylocalip:8005/socket.html 'socket_break' get printed before 'socket_data' in the console. So I see blank page instead of contents of socket.html in my browser.
var http = require("http");
var url = require('url');
var fs = require('fs');
var server = http.createServer(function(request, response){
console.log('Connection');
var path = url.parse(request.url).pathname;
switch(path){
case '/':
response.writeHead(200, {'Content-Type': 'text/html'});
response.write('hello world');
break;
case '/socket.html':
fs.readFile('./socket.html', function(error, data){
if (error){
response.writeHead(404);
response.write("opps this doesn't exist - 404");
console.log('socket_error');
}
else{
response.writeHead(200, {"Content-Type": "text/html"});
response.write(data, "utf8");
console.log('socket_data');
}
});
console.log('socket_break');
break;
default:
response.writeHead(404);
response.write("opps this doesn't exist - 404");
break;
}
response.end();
});
server.listen(8005);
How can I prevent switch/case breaking before reading file and make browser display contents of my socket.html file?
I would stay away from doing synchronous stuff in node.js because when you block, you put everyone making a request on hold. Instead, abstract your routes away from your error handling. Obviously there is some architectural debate as how you want to do this, but this is how I did it to be quick about it :)
var http = require("http");
var url = require('url');
var fs = require('fs');
// Perhaps include this via a require('httpExceptionHandler')
function httpExceptionHandler(req, res) {
return {
404: function() {
res.statusCode = 404;
res.end("opps this doesn't exist - 404");
},
500: function(error) {
res.statusCode = 500;
res.end("internal server error");
}
}
}
// Perhaps include this via a require('routes')
var routes = {
'/': function(server) {
var res = server.response;
res.setHeader('Content-Type', 'text/plain');
res.end('hello world');
},
'/socket.html': function(server) {
var fileStream = fs.createReadStream('socket.html');
fileStream.on('error', server.httpExceptionHandler['500']);
fileStream.pipe(server.response);
}
};
var server = http.createServer(function(request, response){
var path = url.parse(request.url).pathname;
var routeFn = routes[path];
var server = {
httpExceptionHandler: httpExceptionHandler(request, response),
request: request,
response: response
};
if (routeFn) {
// Set some default headers
response.statusCode = 200;
response.setHeader('Content-Type', 'text/html');
// A better design might be to return an action like
// Redirect, Exception, etc... not sure
routeFn(server);
} else {
server.httpExceptionHandler['404']();
}
});
server.listen(8005);
We don't end the response until we are completely done, which enables the above code to function correctly.
The easiest way is to just use return;, but you have to remember to response.end(); inside the callback.
An alternative solution might be to read the files into memory before starting your server and then just doing something like response.writeHead(...); response.end(socketFileBuf);. Obviously you probably wouldn't want to do this if you have a ton of files, have very large files, or want to send arbitrary files. But for simple html files like you probably have here, it should work pretty well and will cut down on response time.
fs.readFile is asynchronous, so it doesn't block while the file is being read.
Use fs.readFileSync instead.
It depends on what you want to accomplish, fs.readFile is asynchronous, so in this case if it's just to print on the console, put the print inside the callback file.
If it's for further execution as well I suggest that you use fs.readFileSync, it's also a lot easier working synchronously if you're new to Node.js.