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

时间:2013-12-03 23:11:54

标签: node.js socket.io

了解node.js和socket.io并完成this tutorial by Daniel Nill。服务器启动没问题。但是,当我导航到localhost: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); 

Socket.html与server.js位于同一目录中,包含此

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

好的,我放弃了这个并转移到this example,开箱即用!

2 个答案:

答案 0 :(得分:2)

初学者。据我所知,Daniel Nill为一个教程编写了一堆代码,但它从未奏效。结果,他只是为初学者增添了一些困惑 - 他声称自己正试图缓解这一点。

  

所以我将switch语句更改为&#39; /socket.html'而不是&#39; socket.html&#39;。

这是一个明显的错误 - 好抓。

  

页面现在加载状态代码200,但没有任何内容呈现   屏幕。屏幕应该说&#34;这是我们的socket.html文件&#34;。什么   给出?

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

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

在我看来Daniel Nill误解了nodejs是如何工作的。也就是说,nodejs不执行一个函数,然后等待作为参数传递的处理函数在执行下一行代码之前完成执行。如果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(),   必须在每个回复中调用。

我测试了它,如果你没有做任何响应。写({1}},你只需要调用response.end(),nodejs将创建一个状态代码为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);

要尽量减少拨打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()处理函数 - 就像丹尼尔尼尔那样;并且你不能在switch语句之后放置response.end()因为response.end()将在传递给fs.readFile()的处理程序函数执行之前执行,这将导致空请求将状态代码200发送到浏览器。

另外,我得到了两个&#34; Connection&#34;单个请求的消息。我输入的工具只显示了当我输入网址时我的浏览器发送的一个请求,如:

http://localhost:8888/

...但是所有浏览器都会发送一个检索/favicon.ico的其他请求。您可以通过编写类似以下内容来证明这种情况:

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文档&#34;从0.9&#34;升级,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浏览器的开发工具以查看控制台) - 所以不要在服务器窗口中查找输出。

===

在本教程的下一部分中,为了简化时间,消除日期,毫秒,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);
  });

});

答案 1 :(得分:-1)

使用response.sendfile而不是手动阅读文件。这让我们快递为您处理内容类型。