S3 поток загрузки файлов с помощью node js
Я пытаюсь найти некоторое решение для потока файла на amazon S3 с помощью сервера node js с требованиями:
- Не храните файл temp на сервере или в памяти. Но до определенного предела не полный файл, буферизация может быть использована для загрузки.
- Нет ограничений на размер загруженного файла.
- Не замораживайте сервер до полной загрузки файла, потому что в случае загрузки большого файла другой запрос время ожидания будет неожиданно
увеличить.
Я не хочу использовать прямую загрузку файлов из браузера, потому что учетные данные S3 должны делиться в этом случае. Еще одна причина для загрузки файла с сервера node js заключается в том, что перед загрузкой файла также может потребоваться некоторая проверка подлинности.
Я попытался достичь этого, используя node -multiparty. Но он не ожидал. Вы можете увидеть мое решение и проблему в https://github.com/andrewrk/node-multiparty/issues/49. Он отлично работает для небольших файлов, но не подходит для файла размером 15 МБ.
Любое решение или альтернатива?
Ответы
Ответ 1
Теперь вы можете использовать потоки с официальным пакетом Amazon SDK для nodejs, и что еще более удивительно, вы, наконец, можете сделать это без знания размер файла заранее, просто передайте поток как Body
:
var fs = require('fs');
var zlib = require('zlib');
var body = fs.createReadStream('bigfile').pipe(zlib.createGzip());
var s3obj = new AWS.S3({params: {Bucket: 'myBucket', Key: 'myKey'}});
s3obj.upload({Body: body})
.on('httpUploadProgress', function(evt) { console.log(evt); })
.send(function(err, data) { console.log(err, data) });
Ответ 2
Дайте https://www.npmjs.org/package/streaming-s3 попытку.
Я использовал его для загрузки нескольких больших файлов параллельно ( > 500 Мб), и он работал очень хорошо.
Он очень настраиваемый, а также позволяет отслеживать загрузку статистики.
Вам не нужно знать общий размер объекта, и ничего не записывается на диск.
Ответ 3
Я использую модуль s3-upload-stream в рабочем проекте здесь.
Есть также несколько хороших примеров из @raynos в его http-framework репозитории.
Ответ 4
В качестве альтернативы вы можете посмотреть - https://github.com/minio/minio-js. Он имеет минимальный набор абстрактных API, реализующих наиболее часто используемые вызовы S3.
Вот пример потоковой загрузки.
$ npm install minio
$ cat >> put-object.js << EOF
var Minio = require('minio')
var fs = require('fs')
// find out your s3 end point here:
// http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region
var s3Client = new Minio({
url: 'https://<your-s3-endpoint>',
accessKey: 'YOUR-ACCESSKEYID',
secretKey: 'YOUR-SECRETACCESSKEY'
})
var outFile = fs.createWriteStream('your_localfile.zip');
var fileStat = Fs.stat(file, function(e, stat) {
if (e) {
return console.log(e)
}
s3Client.putObject('mybucket', 'hello/remote_file.zip', 'application/octet-stream', stat.size, fileStream, function(e) {
return console.log(e) // should be null
})
})
EOF
putObject() - это полностью управляемый вызов одной функции для файлов размером более 5 МБ, который автоматически выполняет многопроцессорное внутреннее соединение. Вы также можете возобновить неудачную загрузку, и она начнется с того места, где ее остановили, проверив ранее загруженные части.
Кроме того, эта библиотека также изоморфна, ее можно использовать и в браузерах.
Ответ 5
Если это помогает кому-либо, у меня есть возможность успешно транслировать с клиента на s3 (без памяти или дискового хранилища):
https://gist.github.com/mattlockyer/532291b6194f6d9ca40cb82564db9d2a
Конечная точка сервера предполагает, что req
является объектом потока, я отправил объект объекта из клиента, который современные браузеры могут отправлять как двоичные данные, и добавленную информацию о файле, заданную в заголовках.
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);
}
});
};
Да, помещая информацию о файле в соглашение о разрыве заголовков, но если вы посмотрите на суть, это намного чище, чем все, что я нашел, используя потоковые библиотеки или multer, busboy и т.д.
+1 для прагматизма и благодаря @SalehenRahman за помощь.