Подтвердить что ты не робот

Загрузите файл в Amazon S3 с помощью NodeJS

У меня возникла проблема при попытке загрузить файл в мой ведро S3. Все работает, за исключением того, что параметры файла не кажутся подходящими. Я использую Amazon S3 sdk для загрузки с nodejs на s3.

Это настройки моих маршрутов:

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

Это функция items.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');
            }
        });
    });
};

Значение параметра Body для строки типа "hello" отлично работает. В соответствии с doc, параметр Body должен принимать (данные буфера, типизированного массива, блока, строки, ReadableStream) объекта. Однако при загрузке объекта файла происходит следующее сообщение об ошибке:

[Error: Unsupported body payload object]

Это файл-объект:

{ 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' }

Любая помощь будет принята с благодарностью!

4b9b3361

Ответ 1

Итак, похоже, что здесь кое-что не так. Основываясь на вашем сообщении, похоже, что вы пытаетесь поддерживать загрузку файлов с помощью промежуточного программного обеспечения connect-multiparty. То, что это промежуточное программное обеспечение делает, - это загрузить загруженный файл, записать его в локальную файловую систему и затем установить req.files в загруженный файл (ы).

Конфигурация вашего маршрута выглядит отлично, проблема связана с вашей функцией items.upload(). В частности, с этой частью:

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

Как я уже говорил в начале моего ответа connect-multiparty записывает файл в локальную файловую систему, вам нужно будет открыть файл, прочитать его, затем загрузить, а затем удалить его в локальной файловой системе.

Сказав, что вы можете обновить свой метод примерно так:

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();
                }
            });
        });
    });
};

Что это значит, это прочитать загруженный файл из локальной файловой системы, затем загрузить его на S3, затем он удалит временный файл и отправит ответ.

Есть несколько проблем с этим подходом. Во-первых, это не так эффективно, как могло бы быть, так как для больших файлов вы будете загружать весь файл, прежде чем писать его. Во-вторых, этот процесс не поддерживает многопользовательскую загрузку больших файлов (я думаю, что отсечка составляет 5 МБ, прежде чем вам придется выполнять многозадачную загрузку).

Вместо этого я хотел бы предложить вам использовать модуль, над которым я работал, под названием S3FS, который предоставляет аналогичный интерфейс для native FS в Node.JS, но абстрагирует некоторые детали, такие как многочастная загрузка и S3 api (также как добавляет некоторые дополнительные функции, такие как рекурсивные методы).

Если бы вы втянули библиотеку S3FS, ваш код выглядел бы примерно так:

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();
    });
};

Что это будет делать, это создать экземпляр модуля для предоставленных ведомостей и учетных данных AWS, а затем создать ведро, если оно не существует. Затем, когда приходит запрос на загрузку файла, мы откроем поток в файл и используем его для записи файла на S3 по указанному пути. Это будет обрабатывать многочастную часть загрузки за кулисами (если необходимо) и имеет преимущество в том, что делается через поток, поэтому вам не нужно ждать, чтобы прочитать весь файл, прежде чем вы начнете его загружать.

Если вы предпочитаете, вы можете изменить код на обратные вызовы из Promises. Или используйте метод pipe() с прослушивателем событий, чтобы определить конец/ошибки.

Если вы ищете некоторые дополнительные методы, ознакомьтесь с документацией для s3fs и не стесняйтесь открыть проблему, если вы ищете некоторые дополнительные методы или проблемы.

Ответ 2

Я нашел следующее, чтобы быть рабочим решением:

npm install aws-sdk


После того, как вы установили aws-sdk, используйте следующий код, заменив значения вашими нужными.

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");

         }

      });

});

Я нашел полное руководство по этому вопросу здесь, если вы ищете ссылки:


Как загрузить файлы (текст/изображение/видео) в Amazon S3, используя node.js

Ответ 3

Или используя обещания:

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);
      }

Ответ 4

var express = require('express')

app = module.exports = express();
var secureServer = require('http').createServer(app);
secureServer.listen(3001);

var aws = require('aws-sdk')
var multer = require('multer')
var multerS3 = require('multer-s3')

    aws.config.update({
    secretAccessKey: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    accessKeyId: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    region: 'us-east-1'
    });
    s3 = new aws.S3();

   var upload = multer({
   storage: multerS3({
    s3: s3,
    dirname: "uploads",
    bucket: "Your bucket name",
    key: function (req, file, cb) {
        console.log(file);
        cb(null, "uploads/profile_images/u_" + Date.now() + ".jpg"); //use  
     Date.now() for unique file keys
    }
  })
   });

 app.post('/upload', upload.single('photos'), function(req, res, next) {

 console.log('Successfully uploaded ', req.file)

 res.send('Successfully uploaded ' + req.file.length + ' files!')

})

Ответ 5

Загрузка файла в AWS s3 и отправка URL-адреса в ответ на доступ к файлу.

Multer - это промежуточное программное обеспечение node.js для обработки multipart/form-data, которое в основном используется для загрузки файлов. Это написано сверху busboy для максимальной эффективности. проверьте этот модуль npm здесь.

Когда вы отправляете запрос, убедитесь, что заголовки имеют Content-Type multipart/form-data. Мы отправляем местоположение файла в ответе, в котором будет указан URL, но если вы хотите получить доступ к этому URL, сделайте корзину общедоступной, иначе вы не сможете получить к ней доступ.

upload.router.js

const express = require('express');
const router = express.Router();
const AWS = require('aws-sdk');
const multer = require('multer');
const storage = multer.memoryStorage()
const upload = multer({storage: storage});

const s3Client = new AWS.S3({
    accessKeyId: 'your_access_key_id',
    secretAccessKey: 'your_secret_access_id',
    region :'ur region'
});

const uploadParams = {
         Bucket: 'ur_bucket_name', 
         Key: '', // pass key
         Body: null, // pass file body
};


router.post('/api/file/upload', upload.single("file"),(req,res) => {
    const params = uploadParams;

    uploadParams.Key = req.file.originalname;
    uploadParams.Body = req.file.buffer;

    s3Client.upload(params, (err, data) => {
        if (err) {
            res.status(500).json({error:"Error -> " + err});
        }
        res.json({message: 'File uploaded successfully','filename': 
        req.file.originalname, 'location': data.Location});
    });
});

module.exports = router;

app.js

const express = require('express');
const app = express();

const router = require('./app/routers/upload.router.js');
app.use('/', router);

// Create a Server
  const server = app.listen(8080, () => {
  console.log("App listening at 8080"); 
})