Direct Browser Upload to S3 with Meteor, jQuery an

2019-03-17 07:42发布

问题:

I have got into almost every resource on the topic, but still need your help to make this work. I want to directly upload files to my S3 directly from the browser in my Meteor app. For this, I provide a signed url to the client just like in this simplified example:

Meteor.methods({
    requestUpload: function(filename) {
        var fut = new Future();
        new Fiber(function() {
            var params = {
                Bucket: MY_BUCKET,
                Key: new Date().getTime() + "_" + filename
            };
            var surl = s3.getSignedUrl('putObject', params, function(err, surl) {
                if (!err) {
                    console.log("signed url: " + surl);
                    fut.return(data);
                } else {
                    console.log("Error signing url " + err);
                    fut.return();
                }
            });
        }).run();
        return fut.wait();
    }
}

The client then calls this method, obtains the signed url which looks like this

https://mybucket.s3-eu-west-1.amazonaws.com/1382890365957_myfile.png?AWSAccessKeyId=AKBLABLA&Expires=1382891265&Signature=BLABLA

and tries to upload the file with a POST request using jQuery like in this snippet:

Template.form.events({
    'submit form': function(e, t) {
        e.preventDefault();
        var fileInput = t.find("input[type=file]");
        for (var i = 0; i < fileInput.files.length; i++) {
            var file = fileInput.files[i];
            Meteor.call("requestUpload", file.name, function(err, surl) {
                if (!err) {
                    console.log("signed url: " + surl);
                    var reader = new FileReader();
                    reader.onload = function(event) {

                    // Here I am trying to upload, it fails
                        $.post(surl, reader.result, function(data, status) {
                            console.log("status: " + status);
                            console.log("data: " + data);
                        });
                    };
                    reader.readAsDataURL(file);
                } else {
                    console.log(err);
                }
            });
        }
    }
});

I want to use jQuery because I thing it's probably a good way to cover a lot of browsers and browser versions. I also checked my CORS configuration for this particular bucket, it looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>POST</AllowedMethod>
        <AllowedMethod>PUT</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

The credentials, that I configure my SDK with on the server are ensured to be alright, they have admin permissions and I am using them all the time for putting and getting objects in the S3 from the server. Also, if I sign a url for a GET call on a private file, the signed url is valid. I am probably doing something wrong with the post call.

Any help is very appreciated!

回答1:

To get this working I had to add a couple of parameters to the s3.getSignedUrl call:

ContentType: mimeType,
Body: '',
"ACL": 'public-read'

Full method:

Meteor.methods({
    requestUpload: function(filename, mimeType) {
        var fut = new Future();
        new Fiber(function() {
            var params = {
                Bucket: MY_BUCKET,
                Key: new Date().getTime() + "_" + filename,
                ContentType: mimeType,
                Body: '',
                "ACL": 'public-read'
            };
            var surl = s3.getSignedUrl('putObject', params, function(err, surl) {
                if (!err) {
                    console.log("signed url: " + surl);
                    fut.return(surl);
                } else {
                    console.log("Error signing url " + err);
                    fut.return();
                }
            });
        }).run();
        return fut.wait();
    }
}


回答2:

Same problem here - I think this is because of Meteor not allowing CORS in the application header. I'm also trying to solve this very urgently.



回答3:

The problem can be that you requesting a SignedUrl for a PUT request but you later on POST the file to S3. You should PUT the file to S3 not POST.

SignedUrls only allow GET and PUT right now.

For more info see this answer: upload-file-from-angularjs-directly-to-amazon-s3-using-signed-url