1

在我的项目中,客户端将请求从具有 id 的服务器下载文件。我必须执行以下操作:

  • 验证来自 mongoDb 的 id
  • 检查扩展
  • 检查文件是否存在
  • 读取文件并将内容写入响应

我正在使用以下代码检查文件并发送响应。

fs.exists(filename, function(exists) {
  if (!exists) {
    res.writeHead(404, '', {
      "Content-Type" : "text/plain"
    })
    res.write("404 Not Found\n");
    res.end();
    return;
  }
  fs.readFile(filename, "binary", function(err, file) {
    if (err) {
      res.writeHead(500, '', {
        "Content-Type" : "text/plain"
      })
      res.write(err + "\n");
      res.end();
      return;
    }
    res.setHeader("Pragma", "public");
    res.setHeader("Cache-Control: private, max-age=3600");
    res.setHeader("Transfer-Encoding:  chunked");
    res.setHeader("Range:  chunked");
    res.writeHead(200, '', {
      "Content-Type" : contentType
    });
    res.write(file, "binary");
    res.end(file, "binary");
  });
});

在几毫秒内,客户端将请求数百个文件。支持的文件类型是图像、音频或视频。

当文件夹中有很多文件时,node.js 会花费太多时间来下载文件。我怎样才能提高性能?

4

1 回答 1

6

我会推荐一些东西。

  1. You should not be using 'binary'. Don't give an encoding at all. By adding the encoding, you are making node do a ton of extra work to convert the file's Buffer object into a binary-encoded string. When you call write again with 'binary' that means node has to then do that same operation in reverse. Also you are passing the file to both end and write, meaning every file you download will contain the file data twice.

  2. I'd recommend against using readFile. Since readFile passes the whole file contents back to you in your file variable, you are requiring node to load the whole contents of the file into RAM, meaning it needs to allocate a ton of buffers and then concatenate them, which is unneeded work.

  3. There is no reason to use exists separately, because if you try to open a file that does not exist, the error will tell you, so checking first is just extra work.

Also, the Transfer-encoding header will be set all by itself, you don't need to do it.

Something like this should be faster:

fs.createReadStream(filename)
    .on('error', function(err){
        if (err.code === 'ENOENT'){
            res.writeHead(404, {
                'Content-type': 'text/plain'
            });
            res.end('404 Not Found\n');
        } else {
            res.writeHead(500, {
                'Content-type': 'text/plain'
            });
            res.end(err + '\n');
        }
    })
    .on('open', function(){
        res.writeHead(200, {
            'Pragma': 'public',
            'Cache-Control': 'private, max-age=3600',
            'Content-type': contentType
        });
    })
    .pipe(res);
于 2012-12-29T15:52:47.797 回答