Node.js 从文件上载节点访问原始文件流

Node.js 从文件上载节点访问原始文件流,node.js,file-upload,amazon-s3,Node.js,File Upload,Amazon S3,我正在创建一个应用程序,它需要上传一些文件并直接发送到S3。我甚至不希望在我的服务器上有tmp文件,所以我使用的是Knox模块,我希望从Fornighous获取原始流,并通过Knox将其发送到S3。我使用Knox做了类似的事情,使用以下代码下载了一个文件: knox.downloads.get(widget.download).on('response',function(sres){ res.writeHead(200, { 'Content-Type':'applic

我正在创建一个应用程序,它需要上传一些文件并直接发送到S3。我甚至不希望在我的服务器上有tmp文件,所以我使用的是Knox模块,我希望从Fornighous获取原始流,并通过Knox将其发送到S3。我使用Knox做了类似的事情,使用以下代码下载了一个文件:

knox.downloads.get(widget.download).on('response',function(sres){
    res.writeHead(200, {
        'Content-Type':'application/zip',
        'Content-Length': sres.headers['content-length'],
        'Content-Disposition':'attachment; filename=' + widget.download
    });
    util.pump(sres, res);
}).end();
现在我想在oposite方向做一些类似的事情(从浏览器上传文件到S3)

到目前为止,我已经编写了一个事件处理程序,用于在上传文件时捕获文件中的每一条数据:

var form = new formidable.IncomingForm();
form.onPart = function(part){
    if(!part.filename){
        form.handlePart(part);
    }else{
        if(part.name == 'download'){
            // Upload to download bucket
            controller.putDownload(part);
        }else{
            // Upload to the image bucket
            controller.putImage(part);
        }
        //res.send(sys.inspect(part));
    }
}
form.parse(req, function(err, fields, files){
    if(err){
        res.json(err);
    }else{
        res.send(sys.inspect({fields:fields, files:files}), {'content-type':'text/plain'});
        //controller.createWidget(res,fields,files);            
    }
});


controller.putDownload = function(part){
    part.addListener('data', function(buffer){
        knox.download.putStream(data,part.filename, function(err,s3res){
            if(err)throwError(err);
            else{
                console.log(s3res);
            }
        });
    })
    knox.downloads.putStream(part, part.filename, function(err,s3res){

        if(err)throwError(err);
        else{
            console.log(s3res);
        }
    });
}

但是数据事件只给了我缓冲区。那么有可能捕获流本身并将其推送到S3吗?

您没有办法捕获流,因为数据必须由用户进行转换。您得到的
缓冲区
是以
缓冲区.长度
为单位的文件内容:这可能是一个问题,因为查看Fornighed的文档,似乎在文件完全上传之前,它无法可靠地报告文件大小,而Knox的
put
方法可能需要这样做

以前从未以这种方式使用过Knox,但您可能会有这样的运气:

controller.putDownload = function(part){
    var req = knox.download.put(part.filename, {
      'Content-Type': 'text/plain'
    });
    part.addListener('data', function(buffer){
    req.write(buffer);
    });
    req.on('response', function(res){
       // error checking
    });
    req.end();
}

有点不确定的反应检查位,但…看看你是否可以鞭策到形状。另外,还有一个可能对您有用的writeup。

您要做的是重写
表单。onPart
方法:

IncomingForm.prototype.onPart = function(part) {
  // this method can be overwritten by the user
  this.handlePart(part);
};
Professional的默认行为是将部件写入文件。你不会想要的。您希望处理要写入knox下载的“part”事件。从这个开始:

form.onPart = function(part) {
    if (!part.filename) {
        // let formidable handle all non-file parts
        form.handlePart(part);
        return;
    }
然后打开knox请求并自行处理原始零件事件:

part.on('data', function(data) {
    req.write(data);
});
part.on('end', function() {
    req.end();
});
part.on('error', function(err) {
    // handle this too
});

另外,如果
请求写入(数据)
返回false,则表示发送缓冲区已满。您应该暂停这个强大的解析器。当您从Knox流中获得
排放
事件时,您应该继续

改用。它支持您想要的这种流媒体。它甚至有一个直接流式传输到s3的例子:

在一个Express中间件中,我使用
强大的
直通
将文件流式上传到s3(在我的例子中,是通过Minio SDK兼容s3的Minio;我相信它也适用于使用相同Minio SDK的AWS s3)

下面是示例代码

const formidable = require('formidable')
const { PassThrough } = require('stream')

const form = new formidable.IncomingForm()
const pass = new PassThrough()

const fileMeta = {}
form.onPart = part => {
  if (!part.filename) {
    form.handlePart(part)
    return
  }
  fileMeta.name = part.filename
  fileMeta.type = part.mime
  part.on('data', function (buffer) {
    pass.write(buffer)
  })
  part.on('end', function () {
    pass.end()
  })
}
form.parse(req, err => {
  if (err) {
    req.minio = { error: err }
    next()
  } else {
    handlePostStream(req, next, fileMeta, pass)
  }
})
handlePostStream
如下所示,供您参考:

const uuidv1 = require('uuid/v1')

const handlePostStream = async (req, next, fileMeta, fileStream) => {
  let filename = uuidv1()

  try {
    const metaData = {
      'content-type': fileMeta.type,
      'file-name': Buffer.from(fileMeta.name).toString('base64')
    }

    const minioClient = /* Get Minio Client*/
    await minioClient.putObject(MINIO_BUCKET, filename, fileStream, metaData)

    req.minio = { post: { filename: `${filename}` } }
  } catch (error) {
    req.minio = { error }
  }
  next()
}

你也可以找到。

我被卡住了,改用多方参与解决了这个问题