Saat ini saya menggunakan plugin node.js yang disebut s3-upload-stream untuk mengalirkan file yang sangat besar ke Amazon S3. Ia menggunakan multipart API dan sebagian besar bekerja dengan sangat baik.
Namun, modul ini menunjukkan usianya dan saya sudah harus mengubahnya (penulis juga sudah menghentikannya). Hari ini saya mengalami masalah lain dengan Amazon, dan saya benar-benar ingin mengambil rekomendasi penulis dan mulai menggunakan aws-sdk resmi untuk menyelesaikan unggahan saya.
TAPI.
SDK resmi tampaknya tidak mendukung penyaluran ke s3.upload()
. Sifat s3.upload adalah Anda harus meneruskan aliran yang dapat dibaca sebagai argumen ke konstruktor S3.
Saya memiliki sekitar 120+ modul kode pengguna yang melakukan berbagai pemrosesan file, dan mereka agnostik ke tujuan akhir keluarannya. Mesin memberi mereka aliran keluaran yang dapat ditulis dalam pipa, dan mereka menyalurkannya ke pipa. Saya tidak dapat memberikan AWS.S3
objek kepada mereka dan meminta mereka untuk memanggilnya upload()
tanpa menambahkan kode ke semua modul. Alasan saya menggunakan s3-upload-stream
adalah karena mendukung pemipaan.
Apakah ada cara untuk membuat aws-sdk menjadi s3.upload()
sesuatu yang dapat saya gunakan untuk menyalurkan streaming?
Jawaban yang agak terlambat, semoga bisa membantu orang lain. Anda bisa mengembalikan streaming yang bisa ditulisi dan promise, sehingga Anda bisa mendapatkan data respons saat upload selesai.
const AWS = require('aws-sdk'); const stream = require('stream'); const uploadStream = ({ Bucket, Key }) => { const s3 = new AWS.S3(); const pass = new stream.PassThrough(); return { writeStream: pass, promise: s3.upload({ Bucket, Key, Body: pass }).promise(), }; }
Dan Anda dapat menggunakan fungsinya sebagai berikut:
const { writeStream, promise } = uploadStream({Bucket: 'yourbucket', Key: 'yourfile.mp4'}); const readStream = fs.createReadStream('/path/to/yourfile.mp4'); const pipeline = readStream.pipe(writeStream);
Sekarang Anda dapat memeriksa janji:
promise.then(() => { console.log('upload completed successfully'); }).catch((err) => { console.log('upload failed.', err.message); });
Atau sebagai
stream.pipe()
return stream.Writable, tujuan (variabel writeStream di atas), memungkinkan untuk rangkaian pipa, kita juga dapat menggunakan kejadiannya:pipeline.on('close', () => { console.log('upload successful'); }); pipeline.on('error', (err) => { console.log('upload failed', err.message) });
sumber
Dalam jawaban yang diterima, fungsi berakhir sebelum unggahan selesai, dan karenanya, itu salah. Kode di bawah disalurkan dengan benar dari aliran yang dapat dibaca.
Unggah referensi
async function uploadReadableStream(stream) { const params = {Bucket: bucket, Key: key, Body: stream}; return s3.upload(params).promise(); } async function upload() { const readable = getSomeReadableStream(); const results = await uploadReadableStream(readable); console.log('upload complete', results); }
Anda juga dapat melangkah lebih jauh dan menampilkan info kemajuan menggunakan
ManagedUpload
seperti:const manager = s3.upload(params); manager.on('httpUploadProgress', (progress) => { console.log('progress', progress) // { loaded: 4915, total: 192915, part: 1, key: 'foo.jpg' } });
Referensi ManagedUpload
Daftar acara yang tersedia
sumber
TypeError: dest.on is not a function
tahu mengapa?dest.on
? Bisakah Anda menunjukkan contoh? @FireBrandTidak ada jawaban yang berhasil untuk saya karena saya ingin:
s3.upload()
s3.upload()
ke aliran lainJawaban yang diterima tidak sesuai dengan yang terakhir. Yang lain mengandalkan api promise, yang tidak praktis untuk digunakan saat bekerja dengan pipa aliran.
Ini adalah modifikasi saya atas jawaban yang diterima.
const s3 = new S3(); function writeToS3({Key, Bucket}) { const Body = new stream.PassThrough(); s3.upload({ Body, Key, Bucket: process.env.adpBucket }) .on('httpUploadProgress', progress => { console.log('progress', progress); }) .send((err, data) => { if (err) { Body.destroy(err); } else { console.log(`File uploaded and available at ${data.Location}`); Body.destroy(); } }); return Body; } const pipeline = myReadableStream.pipe(writeToS3({Key, Bucket}); pipeline.on('close', () => { // upload finished, do something else }) pipeline.on('error', () => { // upload wasn't successful. Handle it })
sumber
Solusi Type Script:
Contoh ini menggunakan:
import * as AWS from "aws-sdk"; import * as fsExtra from "fs-extra"; import * as zlib from "zlib"; import * as stream from "stream";
Dan fungsi async:
public async saveFile(filePath: string, s3Bucket: AWS.S3, key: string, bucketName: string): Promise<boolean> { const uploadStream = (S3: AWS.S3, Bucket: string, Key: string) => { const passT = new stream.PassThrough(); return { writeStream: passT, promise: S3.upload({ Bucket, Key, Body: passT }).promise(), }; }; const { writeStream, promise } = uploadStream(s3Bucket, bucketName, key); fsExtra.createReadStream(filePath).pipe(writeStream); // NOTE: Addition You can compress to zip by .pipe(zlib.createGzip()).pipe(writeStream) let output = true; await promise.catch((reason)=> { output = false; console.log(reason);}); return output; }
Panggil metode ini di suatu tempat seperti:
let result = await saveFileToS3(testFilePath, someS3Bucket, someKey, someBucketName);
sumber
Hal yang perlu diperhatikan di sini dalam jawaban yang paling diterima di atas adalah bahwa: Anda perlu mengembalikan pass dalam fungsi jika Anda menggunakan pipa seperti,
fs.createReadStream(<filePath>).pipe(anyUploadFunction())
function anyUploadFunction () { let pass = new stream.PassThrough(); return pass // <- Returning this pass is important for the stream to understand where it needs to write to. }
Jika tidak, itu akan diam-diam pindah ke berikutnya tanpa menimbulkan kesalahan atau akan melempar kesalahan
TypeError: dest.on is not a function
tergantung pada bagaimana Anda menulis fungsi tersebutsumber
Jika itu membantu siapa pun, saya berhasil melakukan streaming dari klien ke s3:
https://gist.github.com/mattlockyer/532291b6194f6d9ca40cb82564db9d2a
Kode di
req
sisi server mengasumsikan sebagai objek aliran, dalam kasus saya itu dikirim dari klien dengan info file yang ditetapkan di header.const fileUploadStream = (req, res) => { //get "body" args from header const { id, fn } = JSON.parse(req.get('body')); const Key = id + '/' + fn; //upload to s3 folder "id" with filename === fn const params = { Key, Bucket: bucketName, //set somewhere Body: req, //req is a stream }; s3.upload(params, (err, data) => { if (err) { res.send('Error Uploading Data: ' + JSON.stringify(err) + '\n' + JSON.stringify(err.stack)); } else { res.send(Key); } }); };
Ya itu melanggar konvensi tetapi jika Anda melihat intinya itu jauh lebih bersih daripada apa pun yang saya temukan menggunakan multer, busboy dll ...
+1 untuk pragmatisme dan terima kasih kepada @SalehenRahman atas bantuannya.
sumber
Bagi mereka yang mengeluh bahwa ketika mereka menggunakan fungsi unggah s3 api dan file nol byte berakhir di s3 (@ Radar155 dan @gabo) - Saya juga punya masalah ini.
Buat aliran PassThrough kedua dan cukup pipa semua data dari yang pertama ke yang kedua dan teruskan referensi ke detik itu ke s3. Anda dapat melakukan ini dengan beberapa cara berbeda - mungkin cara yang kotor adalah dengan mendengarkan peristiwa "data" pada aliran pertama dan kemudian menulis data yang sama ke aliran kedua - cara yang sama untuk acara "akhir" - panggil saja fungsi akhir pada aliran kedua. Saya tidak tahu apakah ini adalah bug di aws api, versi node atau beberapa masalah lain - tetapi ini mengatasi masalah untuk saya.
Berikut tampilannya:
var PassThroughStream = require('stream').PassThrough; var srcStream = new PassThroughStream(); var rstream = fs.createReadStream('Learning/stocktest.json'); var sameStream = rstream.pipe(srcStream); // interesting note: (srcStream == sameStream) at this point var destStream = new PassThroughStream(); // call your s3.upload function here - passing in the destStream as the Body parameter srcStream.on('data', function (chunk) { destStream.write(chunk); }); srcStream.on('end', function () { dataStream.end(); });
sumber
Mengikuti jawaban lain dan menggunakan AWS SDK terbaru untuk Node.js, ada solusi yang jauh lebih bersih dan sederhana karena fungsi upload s3 () menerima aliran, menggunakan sintaks menunggu dan janji S3:
var model = await s3Client.upload({ Bucket : bucket, Key : key, ContentType : yourContentType, Body : fs.createReadStream(path-to-file) }).promise();
sumber
Saya menggunakan KnexJS dan mengalami masalah saat menggunakan API streaming mereka. Saya akhirnya memperbaikinya, semoga berikut ini akan membantu seseorang.
const knexStream = knex.select('*').from('my_table').stream(); const passThroughStream = new stream.PassThrough(); knexStream.on('data', (chunk) => passThroughStream.write(JSON.stringify(chunk) + '\n')); knexStream.on('end', () => passThroughStream.end()); const uploadResult = await s3 .upload({ Bucket: 'my-bucket', Key: 'stream-test.txt', Body: passThroughStream }) .promise();
sumber
Jika Anda mengetahui ukuran aliran, Anda dapat menggunakan minio-js untuk mengunggah aliran seperti ini:
s3Client.putObject('my-bucketname', 'my-objectname.ogg', stream, size, 'audio/ogg', function(e) { if (e) { return console.log(e) } console.log("Successfully uploaded the stream") })
sumber