Learning about node.js and socket.io and working through this tutorial by Daniel Nill. The server starts no problem. However, when I navigate to localhost:8001/socket.html, I get the default error message. So I changed the switch statement to be '/socket.html' as opposed to 'socket.html'. The page now loads with status code 200, but nothing is rendered to screen. The screen should say "This is our socket.html file". What gives?
The server side js code is
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(__dirname + path, function(error, data){
if (error){
response.writeHead(404);
response.write("opps this doesn't exist - 404");
}
else{
response.writeHead(200, {"Content-Type": "text/html"});
response.write(data, "utf8");
}
});
break;
default:
response.writeHead(404);
response.write("opps this doesn't exist - 404");
break;
}
response.end();
});
server.listen(8001);
Socket.html located in the same directory as server.js contains this
<html>
<head></head>
<body>This is our socket.html file</body>
</html>
Ok I gave up on this and moved over to this example which works right out of the box!
Use response.sendfile instead of reading the file manually. This lets express handle the content-type for you.
Beginner here. As far as I can tell Daniel Nill wrote a bunch of code for a tutorial, and it never worked. As a result, he just added to the confusion for beginners--something he claimed he was trying to alleviate.
That was one obvious error--good catch.
Or, like I'm seeing, if the socket.html file doesn't exist, instead of getting a 404 error I get a status code of 200 (OK) and an empty web page.
The reason the code in the tutorial doesn't work is because Daniel Nill thought he would be clever and not write
response.end()
after everyresponse.write()
. He thought he could just write oneresponse.end()
at the end of all the code.It appears to me that Daniel Nill misunderstood how nodejs works. To wit, nodejs does NOT execute a function and then wait around for the handler function passed as an argument to finish executing before executing the next lines of code. If nodejs actually did that, then we wouldn't need to put our code inside handler functions. Instead, nodejs adds a handler function to a list of handler functions that are to be executed at some time in the future.
Look at the fs.readFile() function in this code:
The handler function for fs.readFile() is this part:
When a browser requests
/socket.html
, nodejs executesfs.readFile()
and then nodejs adds its handler function to the list of handler functions awaiting execution, then nodejs continues on. The next line of code that will execute is theresponse.end()
here:It's apparent to me that before the handler function from fs.readFile() has a chance to execute, nodejs executes that
response.end()
.According to the docs for
response.end()
:I tested it, and if you don't do any response.write()'s and you just call
response.end()
, nodejs will create an empty response with a status code of 200, for example:I think the lesson to learn from Daniel Nill's mistake is that after you give nodejs a handler function, you have no control over where execution will take up after the handler function executes. In fact, code written after the end of a handler function can execute before the handler function executes. As a result, a handler function needs to do everything that needs to be done itself.
Here are the modifications necessary to make the example in the tutorial work correctly:
To minimize the number of times you have to call
response.end()
, you could do this:But you can't refactor the
response.end()
completely out of the handler function--like Daniel Nill did; and you can't put aresponse.end()
after the switch statement because theresponse.end()
will execute before the handler function passed to fs.readFile() has a chance to execute, which will cause an empty request with a status code of 200 to be sent to the browser.Additionally, I was getting two "Connection" messages for a single request. My developer tools only showed one request being sent by my browser when I typed in a url such as:
...but all browsers send an additional request which retrieves
/favicon.ico
. You can prove that is the case by writing something like:To solve the double request problem, I added the if statement:
...which is described here:
http://tinyurl.com/odhs5le
=====
In the next part of the tutorial, in order to see the command line output when using socket.io, you have to start the server using a command like this:
See the nodejs document "Upgrading from 0.9", section
Log differences
here:http://socket.io/docs/migrating-from-0-9/
=====
To get the socket.io part of the code to work, I put the following in
server.js
:Then in
socket.html
, I have this:You could do this:
...but you have to remember that in nodejs the console.log() output goes to the server window, but when javascript executes on a web page, like with socket.html, the console.log() output goes to the web browser's console (display your web browser's development tools to see the console)--so don't look for the output in the server window.
===
In the next part of the tutorial, to stream just the time, eliminating the date, milliseconds, utc offset, etc., which just clutters everything up, you can do this in
server.js
:socket.html
:===
In the next part of the tutorial, to stream data from the client to the server you can do this(note the corrections to the jquery, which is not up to snuff):
socket.html
:server.js
: