18

Please help to implement the dropzone.js to upload the file into Amazon s3 server. Already referred the following link https://github.com/enyo/dropzone/issues/33, but, no idea to implement. kindly help to implement the same. Any dropzone configuration code is required.

davykiash
  • 1,796
  • 5
  • 27
  • 60

1 Answers1

43

For someone who might also jumped into this question, I'd like to share my working scenario (serverlessly with AWS Lambda).

Note: A full example can be found in my Vue S3 Dropzone component, the code related to Dropzone and S3 are actually framework agnostic.

So, basically,

  1. The client (browser) calls an AWS Lambda function to get the pre-signed upload URL for each file being added.
  2. When the pre-signed URL returned in response, the client will trigger dropzone.processFile immediately.
  3. When the file being processing, change dropzone.options.url for the file accordingly.

Hints:

  • As I'm signing a PUT upload-able URL, I'm going to hijack the xhr.send function, otherwise Dropzone will always send file within formData, which is bad for a PUT upload.

The final client code

// In the `accept` function we request a signed upload URL when a file being accepted
accept (file, done) {
  lambda.getSignedURL(file)
    .then((url) => {
      file.uploadURL = url
      done()
      // And process each file immediately
      setTimeout(() => dropzone.processFile(file))
    })
    .catch((err) => {
      done('Failed to get an S3 signed upload URL', err)
    })
}

// Set signed upload URL for each file being processing
dropzone.on('processing', (file) => {
  dropzone.options.url = file.uploadURL
})

The final AWS Lambda code

var AWS = require('aws-sdk')
var s3 = new AWS.S3();
// Make sure you set this env variable correctly
var bucketName = process.env.AWS_BUCKET_NAME

exports.handler = (event, context) => {
    if (!event.hasOwnProperty('contentType')) {
        context.fail({ err: 'Missing contentType' })
    }

    if (!event.hasOwnProperty('filePath')) {
        context.fail({ err: 'Missing filePath' })
    }

    var params = {
        Bucket: bucketName,
        Key: event.filePath,
        Expires: 3600,
        ContentType: event.contentType
    }

    s3.getSignedUrl('putObject', params, (err, url) => {
        if (err) {
            context.fail({ err })
        } else {
            context.succeed({ url })
        }
    })
}

Demo

demo-gif

KF Lin
  • 1,273
  • 2
  • 15
  • 18
  • This saved me so much trouble. Thank you! – PureForm Nov 14 '17 at 04:14
  • 2
    You mention on the code that the `header` must be updated for each file but it doesn't look like you do that, how and where is this done? – moondaisy Mar 28 '18 at 13:30
  • You saved my day. The bounty will be awarded to you tomorrow, thank you so much – Hammerbot Jan 15 '19 at 16:16
  • 1
    @KF Lin - i know i'm responding to a very old thread, but i wanted to check whether your solution comes from a pre-Cognito world or post-Cognito world. If using a Cognito identity, do we still need to have a Lambda function generating signed URLs? – Jimit Raithatha May 03 '19 at 17:00
  • @JimitRaithatha I believe the usefulness of Cognito is not requiring the `key` or filename at the time of generating the signature. – dangel Jun 29 '19 at 02:21
  • for someone new to aws, how do you set up the api gateway to run that lambda function? – Scott Jul 16 '19 at 20:38