' open '和' error '同时使用fs.createReadStream()和EISDIR

Both `open` and `error` at same time with fs.createReadStream() and EISDIR

本文关键字:createReadStream EISDIR fs open error      更新时间:2023-09-26

在实现简单的静态服务中间件时,我在以下代码中偶然发现了这样一个事实:

fs = require('fs');
util = require('util');
stream = fs.createReadStream('/');
stream.on('open', function(fd) { console.log('opened! ' + util.inspect(fd)); });
stream.on('error', function(err) { console.log('error! ' + util.inspect(err)); });

当参数为directory时,会触发openerror事件!

$ node test.js 
opened! 11
error! { [Error: EISDIR, read] errno: 28, code: 'EISDIR' }

我假设我有openerror,从来没有同时。

区分好的open 坏的open 而不需要显式地测试fdstat作为目录的方法是什么?还有其他类似的案例吗?

当您在Node中创建可读流时,代码将尝试打开文件并读取内容(如果没有提供fd)。你可以通过下面的代码看到:

调用createReadStream()创建一个ReadStream对象,如果fd不是一个数字,它将调用this.open():

if (!util.isNumber(this.fd))
  this.open();

这调用fs.open,在一个目录上,我猜打开目录?(为什么允许这样工作而没有错误,这有点奇怪,但代码最终会到达本机绑定层并继续运行。)打开后,代码发出"open"事件并开始读取文件的内容(链接到源文件):

ReadStream.prototype.open = function() {
  var self = this;
  fs.open(this.path, this.flags, this.mode, function(er, fd) {
    if (er) {
      if (self.autoClose) {
        self.destroy();
      }
      self.emit('error', er);
      return;
    }
    self.fd = fd;
    self.emit('open', fd);
    // start the flow of data.
    self.read();
  });
};

在调用fs.read期间导致错误,该错误被发送给ReadStream的回调onRead(链接到源代码):

function onread(er, bytesRead) {
  if (er) {
    if (self.autoClose) {
      self.destroy();
    }
    self.emit('error', er);

因此,由于createReadStream调用立即打开并开始读取文件的内容(如果没有传递文件描述符),因此将像您所看到的那样发出事件。首先是open事件,然后尝试读取文件,但失败了,然后触发error事件。

由于这是一个可读流,您可能需要考虑侦听data事件而不是open事件,以判断这是否是一个可接受的文件,因为您正在立即读取。类似这样:

fs = require('fs');
util = require('util');
stream = fs.createReadStream('/');
stream.on('data', function(chunk) { console.log('data! ' + chunk.toString()); });
stream.on('error', function(err) { console.log('error! ' + util.inspect(err)); });

在测试中,您将在一个文件上点击data,在一个目录上点击error

我以以下方法结束:

  1. fs.open(path, 'r', function(err, fd) { ... })获取文件描述符fd;
  2. fs.fstat(fd, function(err, stats) { ... })stat;
  3. stats.isDirectory()处理EISDIR;
  4. stream = fs.createReadStream(null, { fd: fd, flags: 'r' })最终获得可读文件流;

通过这种方式,我可以保护自己免受可能的文件与目录交换,反之亦然,在检查之后但在打开之前,因为即使有人做了欺骗,其文件描述符仍然有效。

相关文章:
  • 没有找到相关文章