在Node.js中验证上传文件的MIME类型

4
我正在使用node和express处理文件上传,并使用multiparty/busboy和request将它们直接流式传输到转换服务。有没有一种方法可以在将流发送到相应的提供程序之前验证它们是否具有某些特定的文件类型?我尝试了https://github.com/mscdex/mmmagic来从第一个块中获取MIME类型,它运行得很好。我想知道以下工作流程是否可能会起作用:
缓冲文件上传流并检查传入数据的Mime类型。 当检查前几个块且MIME类型正确时,将缓冲区清空到请求流中。 当MIME类型不正确时,发送错误消息并返回。
我试图让这个工作,但似乎存在一些流兼容性问题(node 0.8.x与node 0.10.x流,这些流不受request库支持)。有没有解决这个问题的最佳实践?我是不是看错了呢?
编辑:感谢Paul,我想出了这段代码:

https://gist.github.com/chmanie/8520572

1个回答

9
除了检查客户端请求的 Content-Type 标头之外,我不知道有更好、更聪明的方法来检查 MIME 类型。
您可以使用 转换流 来实现上述解决方案。在此示例中,转换流缓冲一些任意数量的数据,然后将其发送到您的 MIME 检查库中。如果一切正常,它将重新发出数据。随后的块将被原样发出。
var stream = require('readable-stream');
var mmm = require('mmmagic');
var mimeChecker = new stream.Transform();
mimeChecker.data = [];
mimeChecker.mimeFound = false;
mimeChecker._transform = function (chunk, encoding, done) {
  var self = this;

  if (self.mimeFound) {
    self.push(chunk);
    return done();
  }

  self.data.push(chunk);
  if (self.data.length < 10) {
    return done();
  }
  else if (self.data.length === 10) {
    var buffered = Buffer.concat(this.data);
    new mmm.Magic(mmm.MAGIC_MIME_TYPE).detect(buffered, function(err, result) {
      if (err) return self.emit('error', err);
      if (result !== 'text/plain') return self.emit('error', new Error('Wrong MIME'));
      self.data.map(self.push.bind(self));
      self.mimeFound = true;
      return done();
    });
  }
};

你可以将这个转换流导入到任何其他流中,比如请求流(顺便说一下,请求流完全支持Node 0.10流)。
// Usage example
var fs = require('fs');
fs.createReadStream('input.txt').pipe(mimeChecker).pipe(fs.createWriteStream('output.txt'));

编辑:为了更清楚地解释您在Node 0.8和0.10流之间遇到的不兼容性,当您定义一个流并将.on('data')监听器附加到它上面时,它将切换到流模式(又称0.8流),这意味着即使目标没有侦听,它仍会发出数据。如果您启动异步请求到Magic.detect(),这就是可能发生的情况:即使您监听它,数据仍然会流动。


这是一个非常好的答案!你说得完全正确,请求本身支持新的流API。但不幸的是,request使用的node-form-data并不支持:https://github.com/felixge/node-form-data#todo无论如何,这应该能帮助我重新站起来!非常感谢。 - chmanie
抱歉,但上述代码对我无效。在括号和“this”上下文方面进行了一些更改后,我最终编写了此代码(仅供尝试):https://gist.github.com/chmanie/7441515 我不得不引入mimeFound属性,因为上述代码从未到达最后的“else”。但我的解决方案让我留下了损坏的文件(它们缺少一些字节)。 - chmanie
事实上,我最初编写的代码没有经过测试。我已经更新了我的帖子,并提供了一个可用的示例(这里是相关的gist链接https://gist.github.com/PaulMougel/7446104),其中包含一个使用示例。 - Paul Mougel
你刚刚让我的一天变得美好了。再次感谢! - chmanie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接