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

2024-01-11

了解 node.js 和 socket.io 并进行操作Daniel Nill 的本教程 http://www.danielnill.com/blog/nodejs-tutorial-with-socketio/。服务器启动没有问题。但是,当我导航到 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>

好吧,我放弃了这个并转向这个例子 https://stackoverflow.com/questions/9914816/what-is-an-example-of-the-simplest-possible-socket-io-example开箱即用!


初学者在这里。据我所知,丹尼尔·尼尔(Daniel Nill)为教程编写了一堆代码,但它从未起作用。结果,他只是增加了初学者的困惑——他声称他正在努力缓解这一点。

因此,我将 switch 语句更改为“/socket.html”,而不是“socket.html”。

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

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

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

教程中的代码不起作用的原因是 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() here:

    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 一个处理函数之后,你无法控制执行之后将在哪里进行处理函数执行。事实上,在处理函数结束后编写的代码可以执行before处理函数执行。因此,处理函数需要完成所有需要自己完成的事情。

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

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()完全脱离了处理函数——就像 Daniel Nill 所做的那样;你不能把response.end()在 switch 语句之后,因为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 http://tinyurl.com/odhs5le

=====

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

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

请参阅nodejs文档“从0.9升级”,部分Log differences here:

http://socket.io/docs/migration-from-0-9/ 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"});
});

Then in 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 浏览器的开发工具以查看控制台)——因此不要在服务器窗口中查找输出。

===

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

});
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

HTTP 状态代码 200,但页面未加载 Node.js Socket.io -- Node.js Socket.io 教程、Daniel Nill、fs.readFile()、socket.html 的相关文章

随机推荐

  • 为什么切片值有时会过时但永远不会映射值?

    我发现切片映射函数和通道经常被一起提到参考类型 但是我注意到切片某些东西没有表现出任何参考行为 就像它们可能会变得陈旧一样 var s int must update slice value s append s or must use p
  • iOS LinkedIn 身份验证

    我开始使用 Swift 开发 iOS 应用程序 现在我需要创建一个登录系统 然而 我们需要人们提供的 LinkedIn 信息 如何在 iOS 中使用 OAuth2 API 来实现此目的 我已经在 LinkedIn 开发人员区域创建了一个应用
  • 如果集合中已存在临时元素,是否允许“[unordered_]set::emplace()”不构造临时元素?

    这个答案 https stackoverflow com a 77245073 2752075指出了一些有趣的事情 一个天真的实现std unordered set
  • 参数中的 Java“new”关键字

    最近我研究了很多 OOP 设计模式 遇到了一些以前从未见过的奇怪的事情 Button button new Button shell SWT PUSH button addSelectionListener new SelectionAda
  • 跨平台改变java进程优先级的方法

    我需要在单独的 JVM 中与另一个 java 应用程序调用 jar 文件 它非常消耗 CPU 因此它应该以后台优先级运行 以免影响系统的其余部分 有没有跨平台的方法来做到这一点 简单的答案是 没有可移植的方法来更改 Java 中进程的优先级
  • 无法解析方法,为什么?

    方法setDateListener DateListener dl 无法解决 它是公共的 我在包含该方法的 DatePickerFragment java 类的对象上使用它 这里是onCreateView 片段中的方法setDateList
  • C++ 刷新缓冲区

    我知道这里有很多缓冲区问题 但我似乎找不到明确的答案 std cout lt lt write to screen lt lt std endl 我知道这段代码会因为 endl 而写入屏幕并刷新缓冲区 但如果我这样写 std cout lt
  • 如何创建参数化 SQL 查询?我为什么要?

    我听说 每个人 都在使用参数化 SQL 查询来防止 SQL 注入攻击 而不必验证每一条用户输入 你怎么做到这一点 使用存储过程时会自动获取此信息吗 所以我的理解这是非参数化的 cmdText String Format SELECT foo
  • Function 对象是否必要

    创建如下函数是常见且容易的 var f function alert something 那么为什么会有函数对象 like var f new Function alert something 后者很难写 读 我只能想到一种情况 即有人在网
  • Ant在表单中设计DatePicker

    我在用着DatePicker组件来自antd在表单内并想要更改默认值onChange and value中的道具数DatePicker但它不起作用
  • Oauth2 与 Postman 和 IdentityServer4

    我正在尝试在我的 Identity Server 4 上使用 Postman 进行身份验证 它适用于 Net Code 2 但我最近更新到 Net Core 3 并进行了调整 我可以打开登录页面 可以登录 但无法正确重定向 停留在登录页面上
  • Telerik 和 jquery

    我正在开发一个从客户那里收到的应用程序 他们使用了一些 Telerik Web 控件 Telerik 显然包含它自己的 jquery 1 3 2 版本 而我使用的是 1 4 1 我遇到了一些奇怪的 javascript 问题 我想排除旧的
  • 具有默认参数值的 C# 方法不会生成无参数重载?

    最近 我想向扩展方法添加一个可选参数 原来的方法是这样的 public static class Extensions public static bool Foo this IFoo target target DoIt true 这显然
  • QString::split() 和“\r”、“\n”和“\r\n”约定

    我明白那个QString split应该用来获得QStringList从多行QString 但是如果我有一个文件并且我不知道它是来自 Mac Windows 还是 Unix 我不确定是否QString split n 在所有情况下都会很好地
  • 基类的类型不完整

    我有一个基类Point我从中继承Point3D 然而 由于某种原因 班级Point必须始终返回Point3D为操作add 所以我将其包含在我的包含中 这是我的班级Point ifndef POINT H define POINT H inc
  • CodeIgniter 罐身份验证

    我正在利用这个名为坦克验证 http www konyukhov com soft tank auth 希望这个问题不会太小众 因为它特定于这个库 我正在尝试如何在用户注册后立即登录 看来这个库不提供这个功能 我不想开始搞乱这个库 但也许有
  • 从 Django 视图启动 Scrapy

    我使用Scrapy的经验有限 每次使用它总是通过终端的命令 如何从 django 模板获取表单数据 要抓取的 url 以与 scrapy 通信以开始抓取 到目前为止 我只想到从django的视图中获取表单返回的数据 然后尝试进入scrapy
  • require.js +backbone.js:如何构建具有初始化功能的模块?

    我有一个包含三个页面的应用程序 它们是单页界面 这些页面具有相似但不相同的功能 所以我想要有提供通用功能的 javascript 模块 然后每个页面可以定制 覆盖部分通用功能 我使用的是backbone js 所以我要做的是 加载包含常见模
  • 使用Python登录Google帐户进入网站[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我正在制作一个网站 该网站制作分组中人数的图表 来自 www codecamy com 为了实现这一目标 我制定了一个计划 我将有一个服务
  • HTTP 状态代码 200,但页面未加载 Node.js Socket.io -- Node.js Socket.io 教程、Daniel Nill、fs.readFile()、socket.html

    了解 node js 和 socket io 并进行操作Daniel Nill 的本教程 http www danielnill com blog nodejs tutorial with socketio 服务器启动没有问题 但是 当我导