Prześlij plik do Amazon S3 za pomocą NodeJS

Napotkałem problem podczas próby przesłania pliku do mojego wiadra S3. Wszystko działa poza tym, że moje paramtery plików nie wydają się odpowiednie. Używam Amazon S3 sdk do przesyłania z nodejs do s3.

Oto moje ustawienia tras:

var multiparty = require('connect-multiparty'),
    multipartyMiddleware = multiparty();
app.route('/api/items/upload').post(multipartyMiddleware, items.upload);

To jest items.funkcja upload ():

exports.upload = function(req, res) {
    var file = req.files.file;
    var s3bucket = new AWS.S3({params: {Bucket: 'mybucketname'}});
    s3bucket.createBucket(function() {
        var params = {
            Key: file.name,
            Body: file
        };
        s3bucket.upload(params, function(err, data) {
            console.log("PRINT FILE:", file);
            if (err) {
                console.log('ERROR MSG: ', err);
            } else {
                console.log('Successfully uploaded data');
            }
        });
    });
};

Ustawienie Body param na łańcuch podobny do "hello" działa dobrze. Zgodnie z doc, Body param musi pobierać (Bufor, Typed Array, Blob, String, ReadableStream) Dane obiektu. Jednak przesyłanie obiektu pliku nie powiedzie się z następującym komunikatem o błędzie:

[Error: Unsupported body payload object]

To jest obiekt file:

{ fieldName: 'file',
  originalFilename: 'second_fnp.png',
  path: '/var/folders/ps/l8lvygws0w93trqz7yj1t5sr0000gn/T/26374-7ttwvc.png',
  headers: 
   { 'content-disposition': 'form-data; name="file"; filename="second_fnp.png"',
     'content-type': 'image/png' },
  ws: 
   { _writableState: 
      { highWaterMark: 16384,
        objectMode: false,
        needDrain: true,
        ending: true,
        ended: true,
        finished: true,
        decodeStrings: true,
        defaultEncoding: 'utf8',
        length: 0,
        writing: false,
        sync: false,
        bufferProcessing: false,
        onwrite: [Function],
        writecb: null,
        writelen: 0,
        buffer: [],
        errorEmitted: false },
     writable: true,
     domain: null,
     _events: { error: [Object], close: [Object] },
     _maxListeners: 10,
     path: '/var/folders/ps/l8lvygws0w93trqz7yj1t5sr0000gn/T/26374-7ttwvc.png',
     fd: null,
     flags: 'w',
     mode: 438,
     start: undefined,
     pos: undefined,
     bytesWritten: 261937,
     closed: true },
  size: 261937,
  name: 'second_fnp.png',
  type: 'image/png' }

Każda pomoc będzie bardzo mile widziana!

Author: Maximus S, 2015-01-19

3 answers

Wygląda na to, że kilka rzeczy idzie nie tak. Na podstawie Twojego posta wygląda na to, że próbujesz obsługiwać przesyłanie plików za pomocą oprogramowania pośredniczącego connect-multiparty. Oprogramowanie pośredniczące pobiera przesłany plik, zapisuje go do lokalnego systemu plików, a następnie ustawia req.files do przesłanych plików.

Konfiguracja trasy wygląda dobrze, problem wygląda z funkcją items.upload(). W szczególności z tą częścią:

var params = {
  Key: file.name,
  Body: file
};

Jak wspomniałem na początku mojej answer connect-multiparty zapisuje plik do lokalnego systemu plików, więc musisz go otworzyć i przeczytać, a następnie przesłać, a następnie usunąć na lokalnym systemie plików.

To powiedziało, że możesz zaktualizować swoją metodę do czegoś takiego jak:

var fs = require('fs');
exports.upload = function (req, res) {
    var file = req.files.file;
    fs.readFile(file.path, function (err, data) {
        if (err) throw err; // Something went wrong!
        var s3bucket = new AWS.S3({params: {Bucket: 'mybucketname'}});
        s3bucket.createBucket(function () {
            var params = {
                Key: file.originalFilename, //file.name doesn't exist as a property
                Body: data
            };
            s3bucket.upload(params, function (err, data) {
                // Whether there is an error or not, delete the temp file
                fs.unlink(file.path, function (err) {
                    if (err) {
                        console.error(err);
                    }
                    console.log('Temp File Delete');
                });

                console.log("PRINT FILE:", file);
                if (err) {
                    console.log('ERROR MSG: ', err);
                    res.status(500).send(err);
                } else {
                    console.log('Successfully uploaded data');
                    res.status(200).end();
                }
            });
        });
    });
};

To co robi to odczytuje przesłany plik z lokalnego systemu plików, następnie przesyła go do S3, a następnie usuwa plik tymczasowy i wysyła odpowiedź.

Jest kilka problemów z tym podejściem. Po pierwsze, nie jest tak wydajny jak może tak być, ponieważ w przypadku dużych plików będziesz ładował cały plik przed jego zapisaniem. Po drugie, ten proces nie obsługuje przesyłania wieloczęściowego dla dużych plików (myślę, że odcięcie wynosi 5 Mb, zanim trzeba zrobić przesyłanie wieloczęściowe).

Sugerowałbym zamiast tego użycie modułu, nad którym pracowałem o nazwie S3FS , który zapewnia podobny interfejs do natywnego FS w węźle.JS, ale usuwa niektóre szczegóły, takie jak wieloczęściowy upload i S3 api (a także dodaje kilka dodatkowych funkcji, takich jak metody rekurencyjne).

Gdybyś miał ściągnąć bibliotekę s3fs Twój kod wyglądałby mniej więcej tak:

var fs = require('fs'),
    S3FS = require('s3fs'),
    s3fsImpl = new S3FS('mybucketname', {
        accessKeyId: XXXXXXXXXXX,
        secretAccessKey: XXXXXXXXXXXXXXXXX
    });

// Create our bucket if it doesn't exist
s3fsImpl.create();

exports.upload = function (req, res) {
    var file = req.files.file;
    var stream = fs.createReadStream(file.path);
    return s3fsImpl.writeFile(file.originalFilename, stream).then(function () {
        fs.unlink(file.path, function (err) {
            if (err) {
                console.error(err);
            }
        });
        res.status(200).end();
    });
};

Spowoduje to utworzenie instancji modułu dla dostarczonych poświadczeń bucket i AWS, a następnie utworzenie wiadra, jeśli nie istnieje. Następnie, gdy pojawi się żądanie przesłania pliku, otworzymy strumień do pliku i użyjemy go do zapisu pliku Na S3 do określonej ścieżki. Poradzi sobie z tym. wieloczęściowy fragment przesyłania za kulisami (w razie potrzeby)i ma tę zaletę, że jest wykonywany za pośrednictwem strumienia, więc nie musisz czekać, aby przeczytać cały plik przed rozpoczęciem przesyłania.

Jeśli wolisz, możesz zmienić kod na callbacks z Promises. Lub użyj metody pipe () z detektorem zdarzeń, aby określić koniec / błędy.

Jeśli szukasz dodatkowych metod, zajrzyj do dokumentacji s3fs i otwórz problem, jeśli szukasz dodatkowych metod lub masz problemy.

 78
Author: David,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-13 23:19:15

Znalazłem następujące rozwiązanie::

npm install aws-sdk


Po zainstalowaniu aws-sdk użyj poniższego kodu, zastępującego wartości w razie potrzeby.

var AWS = require('aws-sdk');
var fs =  require('fs');

var s3 = new AWS.S3();

// Bucket names must be unique across all S3 users

var myBucket = 'njera';

var myKey = 'jpeg';
//for text file
//fs.readFile('demo.txt', function (err, data) {
//for Video file
//fs.readFile('demo.avi', function (err, data) {
//for image file                
fs.readFile('demo.jpg', function (err, data) {
  if (err) { throw err; }



     params = {Bucket: myBucket, Key: myKey, Body: data };

     s3.putObject(params, function(err, data) {

         if (err) {

             console.log(err)

         } else {

             console.log("Successfully uploaded data to myBucket/myKey");

         }

      });

});

Znalazłem tutaj kompletny samouczek na ten temat, jeśli szukasz referencji ::


Jak przesłać pliki (tekst/obraz / wideo) w amazon S3 za pomocą węzła.js
 9
Author: Rishabh.IO,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-08 17:47:15

Lub używając obietnic:

const AWS = require('aws-sdk');
  AWS.config.update({
    accessKeyId: 'accessKeyId',
    secretAccessKey: 'secretAccessKey',
    region: 'region'
  });

let params = {
        Bucket: "yourBucketName",
        Key: 'someUniqueKey',
        Body: 'someFile'
      };
      try {
        let uploadPromise = await new AWS.S3().putObject(params).promise();
        console.log("Successfully uploaded data to bucket");
      } catch (e) {
        console.log("Error uploading data: ", e);
      }
 1
Author: milosnkb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-17 14:01:13