How to upload an image to s3 in Node

2019-07-12 22:56发布

问题:

Posting a file from my react front end to the node back end.

request
.post('/api/upload')
.field('fileName', res.body.text)
.field('filePath', `/${this.s3DirName}`) // set dynamically
.attach('file', data.file)
.end((err2, res2) => {
    if (err2){ 
        console.log('err2', err2);
        this.setState({ error: true, sending: false, success: true });
    }else{
        console.log('res2', res2);
        this.setState({ error: false, sending: false, success: true });
    }

});

and then on my node backend I want to upload to s3. I am using busboy to be able to get the multipart file that is posted and then the aws sdk to send to my s3 bucket.

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

const s3 = new AWS.S3({
  apiVersion: '2006-03-01',
  params: {Bucket: 'bucketName'}
});

static upload(req, res) {

    req.pipe(req.busboy);

    req.busboy.on('file', (fieldname, file, filename) => {
      console.log("Uploading: " + filename);
      console.log("file: ", file);

      var params = {
        Bucket: 'bucketName',
        Key: filename,
        Body: file
      };

      s3.putObject(params, function (perr, pres) {
        if (perr) {
          console.log("Error uploading data: ", perr);
          res.send('err')
        } else {
          console.log("Successfully uploaded data to myBucket/myKey");
          res.send('success')
        }
      });

    });

}

But I get error

Error uploading data:  { Error: Cannot determine length of [object Object]

Am I correct in uploading the file object directly or do I need to parse it? Perhaps I should be using uploadFile instead of putObject?

If it helps, this is the output of my console.logs where I log the file and file name

Uploading: 31032017919Chairs.jpg
file:  FileStream {
  _readableState: 
   ReadableState {
     objectMode: false,
     highWaterMark: 16384,
     buffer: BufferList { head: null, tail: null, length: 0 },
     length: 0,
     pipes: null,
     pipesCount: 0,
     flowing: null,
     ended: false,
     endEmitted: false,
     reading: false,
     sync: true,
     needReadable: false,
     emittedReadable: false,
     readableListening: false,
     resumeScheduled: false,
     defaultEncoding: 'utf8',
     ranOut: false,
     awaitDrain: 0,
     readingMore: false,
     decoder: null,
     encoding: null },
  readable: true,
  domain: null,
  _events: { end: [Function] },
  _eventsCount: 1,
  _maxListeners: undefined,
  truncated: false,
  _read: [Function] }

回答1:

Referring to the similar discussion: Difference between upload() and putObject() for uploading a file to S3?

The problem is s3.putObject needs to know Body length before upload. In your case, it cannot determine length of the stream (because it's being streamed, it's unknown from the beginning), so s3.upload is more suitable. From the docs:

http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#upload-property