いくつかのファイルのアップロードを取得して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にプッシュすることは可能ですか?
やりたいことは、_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を再開する必要があります。
代わりに multiparty を使用してください。それはあなたが望むようにこの種のストリーミングをサポートします。 s3に直接ストリーミングする例もあります: https://github.com/superjoe30/node-multiparty/blob/master/examples/s3.js
Expressミドルウェアでは、formidable
をPassThrough
と一緒に使用して、ファイルを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のソースコード 、および その単体テスト も見つけることができます。