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 за помощь.