[新手]Nodejs中在一个简单的hello遇到的Buffer和data事件的问题

[新手]Nodejs中在一个简单的hello遇到的Buffer和data事件的问题

我用浏览器访问一次 http://127.0.0.1 ,为什么会打印出两次一样的内容?'data’是被触发了两次么? 还有,不太清楚读取的buffer前3个字节是什么,后面才是html的数据,但没了这三个字节浏览器会显示乱码

打印: D:\nodejs\test>node test.js server start < Buffer ef bb bf 3c 68 31 3e 68 68 68 68 20 e6 88 91 3c 2f 68 31 3e > 20 < Buffer ef bb bf 3c 68 31 3e 68 68 68 68 20 e6 88 91 3c 2f 68 31 3e > 20

hello.html内容: < h1>hhhh 我< /h1>

代码: var http = require(‘http’); var fs = require(‘fs’);

http.createServer(function (req, res) { var rStream = fs.createReadStream(’./hello.html’); var datas = []; rStream.on(‘data’, function (data) { console.log(data); console.log(data.length); datas.push(data); }); rStream.on(‘end’, function () { var buf = Buffer.concat(datas); res.writeHead(200, {‘Content-Type’: ‘text/html’}); res.end(buf); }); }).listen(80); console.log(‘server start’);


3 回复

根据你的描述和提供的代码片段,你遇到了两个主要问题:

  1. data 事件被触发两次:这通常是因为每次 data 事件被触发时,读取流会传递一部分数据。如果你没有正确地处理这些部分数据,可能会导致多次输出。
  2. 前三个字节的问题ef bb bf 这些字节是 UTF-8 编码中的 BOM(Byte Order Mark),用于标识文件以 UTF-8 编码。

示例代码及解释

让我们修改一下你的代码,确保我们正确处理 data 事件,并且去除 BOM。

var http = require('http');
var fs = require('fs');

http.createServer(function (req, res) {
    var rStream = fs.createReadStream('./hello.html');
    var datas = [];

    rStream.on('data', function (data) {
        console.log(data.toString());
        console.log(data.length);
        datas.push(data);
    });

    rStream.on('end', function () {
        // 拼接所有数据片段
        var buf = Buffer.concat(datas);

        // 去除BOM
        if (buf[0] === 0xEF && buf[1] === 0xBB && buf[2] === 0xBF) {
            buf = buf.slice(3);
        }

        res.writeHead(200, {'Content-Type': 'text/html'});
        res.end(buf);
    });
}).listen(80);

console.log('server start');

解释

  1. data 事件处理:每次 data 事件被触发时,我们将数据片段推入 datas 数组,并打印其长度。
  2. 拼接数据:在 end 事件中,我们将所有数据片段拼接到一个 Buffer 中。
  3. 去除 BOM:检查拼接后的 Buffer 是否包含 BOM 字节(0xEF BB BF),如果存在,则从第四个字节开始截取数据。
  4. 发送响应:将处理后的 Buffer 发送到客户端。

这样处理后,你可以避免重复输出和 BOM 导致的乱码问题。希望这能解决你的问题!


在 function(req,res)后添加了一行打印 console.log(‘new req’)发觉是发了两次请求……汗,奇怪了

根据你的描述,你在处理文件流读取时遇到了一些问题,特别是在 data 事件中接收到的 Buffer 对象以及 HTML 文件的编码问题。

问题分析

  1. data 事件被触发两次:这通常是因为数据量较大,分成了多个块进行传输。
  2. 前三个字节:这些字节实际上是 UTF-8 的 BOM(Byte Order Mark),即 ef bb bf。BOM 用于标记文件的编码格式,对于大多数现代浏览器来说,可以忽略它。
  3. 浏览器显示乱码:这是由于浏览器无法正确解析没有去除 BOM 的数据。

示例代码

var http = require('http');
var fs = require('fs');

http.createServer(function (req, res) {
    var rStream = fs.createReadStream('./hello.html');
    
    rStream.on('data', function (data) {
        // console.log(data);  // 可以注释掉,避免输出过多数据
        console.log(data.length);
    });

    let datas = [];
    rStream.on('data', function (data) {
        datas.push(data);
    });

    rStream.on('end', function () {
        // 拼接所有数据块
        var buf = Buffer.concat(datas);

        // 去除 BOM(可选)
        if (buf.slice(0, 3).equals(new Buffer([0xEF, 0xBB, 0xBF]))) {
            buf = buf.slice(3);
        }

        res.writeHead(200, {'Content-Type': 'text/html'});
        res.end(buf);
    });
}).listen(80);

console.log('server start');

解释

  1. data 事件:每次接收到数据块时,将其添加到数组 datas 中。
  2. 拼接数据:在 end 事件中,使用 Buffer.concat 方法将所有数据块合并成一个完整的 Buffer
  3. 去除 BOM:检查缓冲区的前三个字节是否为 BOM,并在需要时去除它们。
  4. 发送响应:将最终的 Buffer 发送给客户端。

这样可以确保即使文件较大,数据也能正确地被读取并发送给浏览器,同时不会出现乱码问题。

回到顶部