HTTP状态代码200,但页面不加载Node.js Socket.io – Node.js教程随着Socket.io,Daniel Nill,fs.readFile(),socket.html

学习node.js和socket.io,并通过Daniel Nill的本教程进行学习 。 服务器启动没有问题。 但是,当我导航到本地主机:8001 / socket.html,我得到了默认的错误信息。 所以我把switch语句改成了'/socket.html',而不是'socket.html'。 现在页面加载状态码200,但是没有任何东西被渲染到屏幕上。 屏幕应该显示“这是我们的socket.html文件”。 是什么赋予了?

服务器端的JS代码是

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); 

位于与server.js相同的目录中的Socket.html包含这个

 <html> <head></head> <body>This is our socket.html file</body> </html> 

好吧,我放弃了这一点,并转移到这个开箱即用的例子 !

初学者在这里。 据我所知,Daniel Nill为一个教程写了一堆代码,而且从来没有用过。 结果,他刚刚join了混乱的初学者 – 他声称他试图减轻。

所以我把switch语句改成了'/socket.html',而不是'socket.html'。

这是一个明显的错误 – 好的结果。

现在页面加载状态码200,但是没有任何东西被渲染到屏幕上。 屏幕应该显示“这是我们的socket.html文件”。 是什么赋予了?

或者,正如我所看到的,如果socket.html文件不存在,而不是得到一个404错误,我得到一个200(OK)的状态代码和一个空的网页。

本教程中的代码不起作用的原因是因为Daniel Nill认为他会很聪明,并且不会在每个response.write()之后写入response.write() 。 他认为他可以在所有代码的末尾写一个response.end()

在我看来,Daniel Nill误解了nodejs是如何工作的。 换句话说,nodejs不会执行一个函数,然后等待处理函数作为parameter passing,以在执行下一行代码之前完成执行。 如果nodejs真的这样做,那么我们不需要把我们的代码放在处理函数中。 相反,nodejs将一个处理函数添加到将来在某个时间执行的处理函数列表中。

看这个代码中的fs.readFile()函数:

 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(); 

fs.readFile()的处理函数是这个部分:

  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"); } }); 

当浏览器请求/socket.html ,nodejs执行fs.readFile() ,然后nodejs将处理函数添加到等待执行的处理函数列表中,然后nodejs继续。 下一行将执行的代码是response.end()

  default: response.writeHead(404); response.write("opps this doesn't exist - 404"); break; } response.end(); //<====HERE ****** 

很明显,在fs.readFile()的处理函数有机会执行之前,nodejs执行response.end()

根据response.end()的文档:

response.end([data],[encoding])
这个方法发信号给服务器所有的响应标题和主体已经被发送; 该服务器应该考虑完成此消息。 response.end()方法必须在每个响应中调用。

我testing了一下,如果你没有做任何response.write(),你只需要调用response.end() ,nodejs将创build一个空的响应,状态码为200,例如:

  switch(path) { case '/': //resp.writeHead(200, {'Content-Type': 'text/html'} ); //resp.write('<h3>Root page</h3>'); resp.end(); break; 

我认为从Daniel Nill的错误中吸取的教训是,在给nodejs一个处理函数之后,你无法控制处理函数执行后执行的地方。 事实上,在处理函数结束之后编写的代码可以在执行处理函数之前执行。 因此,一个处理函数需要做所有需要完成的事情。

以下是使本教程中的示例正确工作所必需的修改:

 var http = require('http'); var url = require('url'); var fs = require('fs'); var server = http.createServer(function(requ, resp) { //requ.url => everything after the host--including the query string //url.parse(requ.url).pathname => the portion of requ.url before the query string var path = url.parse(requ.url).pathname; //The following is so that the automatic request that all browsers make //for favicon.ico (which for some reason is not logged by any developer //tools) will not display a 'connection' message: if (path == '/favicon.ico') { resp.writeHead(200, {'Content-Type': 'image/x-icon'} ); resp.end(); return; //Terminate execution of this function, skipping the code below. } //Router: switch(path) { case '/': resp.writeHead(200, {'Content-Type': 'text/html'} ); resp.write('<h3>Root page</h3>'); resp.end(); break; case '/socket.html': fs.readFile(__dirname + path, function(error, data) { if (error) { console.log('file error'); resp.writeHead(404); resp.write("oops, this doesn't exist - 404"); resp.end(); } else { console.log('no file error'); resp.writeHead(200, {'Content-Type': 'text/html'} ); resp.write(data, 'utf8'); resp.end(); } }); break; default: resp.writeHead(404); resp.write("oops, this doesn't exist - 404"); resp.end(); break; } console.log('Connection'); }); port = 8888; console.log('Server listening on port ' + port); server.listen(port); 

为了尽量减less你需要调用response.end() ,你可以这样做:

 var http = require('http'); var url = require('url'); var fs = require('fs'); var server = http.createServer(function(requ, resp) { //console.log('request url: ' + requ.url); //requ.url => everything after the host--including the query string //url.parse(requ.url).pathname => the portion of requ.url before the query string var path = url.parse(requ.url).pathname; //The following is so that the automatic request that all browsers make //for favicon.ico (which for some reason is not logged by any developer //tools) will not cause a 'connection' message: if (path == '/favicon.ico') { resp.writeHead(200, {'Content-Type': 'image/x-icon'} ); resp.end(); return; } //Router: switch(path) { case '/': resp.writeHead(200, {'Content-Type': 'text/html'} ); resp.write('<h3>Root page</h3>'); resp.end(); break; case '/socket.html': fs.readFile(__dirname + path, function(error, data) { if (error) { console.log('file error'); resp.writeHead(404); resp.write("oops, this doesn't exist - 404"); //resp.end(); } else { console.log('no file error'); resp.writeHead(200, {'Content-Type': 'text/html'} ); resp.write(data, 'utf8'); //resp.end(); } resp.end(); }); break; default: resp.writeHead(404); resp.write("oops, this doesn't exist - 404"); resp.end(); break; } //resp.end(); console.log('Connection'); }); port = 8888; console.log('Server listening on port ' + port); server.listen(port); 

但是你不能将response.end()完全从处理函数中重构出来 – 就像Daniel Nill所做的那样; 你不能在switch语句后面放一个response.end() ,因为response.end()会在处理函数传递给fs.readFile()之前执行,因此会执行一个空的请求, 200的状态码被发送到浏览器。

此外,我得到两个“连接”消息的单个请求。 我的开发人员工具只显示了一个请求被我的浏览器发送,当我键入一个url,如:

 http://localhost:8888/ 

…但所有的浏览器发送一个额外的请求,检索/favicon.ico 。 你可以通过写一些东西来certificate是这样的:

 var server = http.createServer(function(requ, resp) { console.log('request url: ' + requ.url); 

为了解决双重请求问题,我添加了if语句:

 if (path == '/favicon.ico') {... 

…在这里描述:

http://tinyurl.com/odhs5le

=====

在本教程的下一部分,为了在使用socket.io时看到命令行输出,必须使用如下命令启动服务器:

  $ DEBUG=socket.io:* node server.js 

请参阅nodejs文档“从0.9升级”一节,这里是Log differences

http://socket.io/docs/migrating-from-0-9/

=====

为了让代码的socket.io部分起作用,我在server.js了以下内容:

 var http = require('http'); var url = require('url'); var fs = require('fs'); var io = require('socket.io'); //New code var server = http.createServer(function(requ, resp) { ... ... ... }); port = 8888; console.log('Server listening on port ' + port); server.listen(port); //New code: var websockets_listener = io.listen(server); websockets_listener.sockets.on('connection', function(socket){ socket.emit('server message', {"message": "hello world"}); }); 

然后在socket.html ,我有这样的:

 <html> <head> <script src="/socket.io/socket.io.js"></script> </head> <body> <div>This is our socket.html file</div> <div id="message"></div> <script> var socket = io.connect(); //More recent versions of socket.io allow you to simply write: //var socket = io(); //which both creates the socket and by default connects to //the same host that served this page. //See: http://socket.io/get-started/chat/, section Integrating Socket.IO socket.on('server message', function(data) { document.getElementById('message').innerHTML = data.message; }); </script> </body> </html> 

你可以这样做:

  socket.on('server message', function(data) { console.log(data.message); }); 

…但是你必须记住,在nodejs中,console.log()输出进入服务器窗口,但是当javascript在网页上执行时,就像使用socket.html一样,console.log()输出转到web浏览器的控制台(显示您的Web浏览器的开发工具以查看控制台) – 所以不要在服务器窗口中查找输出。

===

在本教程的下一部分,为了简化时间,删除date,毫秒,utc偏移量等,这些只是将所有内容混淆起来,您可以在server.js执行此操作:

 var websockets_listener = io.listen(server); websockets_listener.sockets.on('connection', function(socket){ setInterval(function() { var now = new Date(); socket.emit('time', {local_time: now.toLocaleTimeString()}) }, 1000); }); 

socket.html

 <html> <head> <script src="/socket.io/socket.io.js"></script> </head> <body> <div>This is our socket.html file</div> <div id="message"></div> <script> var socket = io.connect(); socket.on('time', function(data) { document.getElementById('message').innerHTML = data.local_time; }); </script> </body> </html> 

===

在本教程的下一部分,要将数据从客户端传输到服务器,您可以执行此操作(请注意对jQuery的更正,但不能满足要求):

socket.html

 <html> <head> <script src="/socket.io/socket.io.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.js"></script> </head> <body> <div>This is our socket.html file</div> <div id="time"></div> <textarea id="text"></textarea> <script> var socket = io.connect(); socket.on('time', function(data) { $('#time').html(data.local_time); }); //Because the html above has already been parsed by the time this //js executes, there is no need for document.ready(): $('#text').on('keypress', function(event) { var keycode = event.which; socket.emit('client data', {letter: String.fromCharCode(keycode)} ); }); </script> </body> </html> 

server.js

 var http = require('http'); var url = require('url'); var fs = require('fs'); var io = require('socket.io'); var server = http.createServer(function(requ, resp) { ... ... ... }); port = 8888; console.log('Server listening on port ' + port); server.listen(port); var websockets_listener = io.listen(server); //websockets_listener.set('log level', 1); //Rather than writing the previous line(which doesn't work anymore) //just stop the server and restart it using this command: //$ node server.js //...instead of: //$ DEBUG=socket.io:* node server.js websockets_listener.sockets.on('connection', function(socket){ setInterval(function() { var now = new Date(); socket.emit('time', {local_time: now.toLocaleTimeString()}) }, 1000); socket.on('client data', function(data) { process.stdout.write(data.letter); }); }); 

使用response.sendfile而不是手动读取文件。 这可以让你快速处理内容types。