【问题标题】:HTTP Status Code 200 but page does not load Node.js Socket.io -- Node.js Tutorial With Socket.io, Daniel Nill, fs.readFile(), socket.htmlHTTP 状态代码 200 但页面未加载 Node.js Socket.io -- 使用 Socket.io 的 Node.js 教程,Daniel Nill,fs.readFile(),socket.html
【发布时间】:2013-12-20 05:54:15
【问题描述】:

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

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

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

好吧,我放弃了,转而使用 this example,它开箱即用!

【问题讨论】:

    标签: node.js socket.io


    【解决方案1】:

    这里是初学者。据我所知,Daniel Nill 为教程编写了一堆代码,但从未奏效。结果,他只是增加了初学者的困惑——他声称他试图缓解这一点。

    所以我将 switch 语句更改为“/socket.html”而不是“socket.html”。

    这是一个明显的错误——很好。

    页面现在加载状态码 200,但没有呈现任何内容 屏幕。屏幕应该显示“这是我们的 socket.html 文件”。什么 给?

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

    教程中的代码不起作用的原因是丹尼尔尼尔认为他会很聪明,不会在每个response.write()之后写response.end()。他认为他可以在所有代码的末尾写一个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([数据], [编码])
    此方法向服务器发出信号 已发送所有响应标头和正文;那台服务器 应该认为这个消息是完整的。方法,response.end(), 必须在每次响应时调用。

    我测试过,如果你不做任何response.write(),而只是调用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);
    

    但是您不能像 Daniel Nill 那样将 response.end() 完全重构出处理函数;并且您不能在 switch 语句之后放置response.end(),因为response.end() 将在传递给 fs.readFile() 的处理函数有机会执行之前执行,这将导致状态码为 200 的空请求发送到浏览器。

    此外,我在一个请求中收到了两条“连接”消息。当我输入如下网址时,我的开发人员工具仅显示浏览器发送了一个请求:

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

    ===

    在教程的下一部分中,要仅流式传输时间,消除日期、毫秒、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);
      });
    
    });
    

    【讨论】:

      【解决方案2】:

      使用response.sendfile 而不是手动读取文件。这让 express 为您处理内容类型。

      【讨论】:

      • 教程与express无关。
      猜你喜欢
      • 1970-01-01
      • 2014-04-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-22
      • 2016-03-20
      • 2013-10-25
      相关资源
      最近更新 更多