web-dev-qa-db-ja.com

ノードを形成可能なファイルアップロードから生ファイルストリームにアクセスする

いくつかのファイルのアップロードを取得してS3に直接送信するアプリケーションを作成しています。サーバーにtmpファイルを置きたくないので、Knoxモジュールを使用しており、Formidableからrawストリームを取得して、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();

次に、反対方向(ブラウザーから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にプッシュすることは可能ですか?

41
Dave Long

やりたいことは、_Form.onPart_メソッドをオーバーライドすることです。

_IncomingForm.prototype.onPart = function(part) {
  // this method can be overwritten by the user
  this.handlePart(part);
};
_

Formidableのデフォルトの動作は、パーツをファイルに書き込むことです。あなたはそれを望まない。 'part'イベントを処理して、knoxダウンロードに書き込みます。これから始めましょう:

_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
});
_

ボーナスとして、req.write(data)がfalseを返した場合、送信バッファがいっぱいであることを意味します。 Formidableパーサーを一時停止する必要があります。 Knoxストリームからdrainイベントを取得したら、Formidableを再開する必要があります。

20
kgilpin

代わりに multiparty を使用してください。それはあなたが望むようにこの種のストリーミングをサポートします。 s3に直接ストリーミングする例もあります: https://github.com/superjoe30/node-multiparty/blob/master/examples/s3.js

6
andrewrk

Expressミドルウェアでは、formidablePassThroughと一緒に使用して、ファイルをS3(私の場合はMinio SDKを介してS3と互換性のあるMinioに)にストリームアップロードします。同じMinioSDKを搭載したAWSS3も)

これがサンプルコードです。

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()
}

GitHubのソースコード 、および その単体テスト も見つけることができます。

1
Yuci