How to upload files to AWS-S3 with Angular $http PUT

2.4k Views Asked by At

In my Angular application I try to upload a file to AWS-S3 with $http.put(url, file).

However it's not working, I get back a HTTP-403 Forbidden telling me that the signature s3 calculated differs from the one I provided BUT if I make the same request with curl like curl -X PUT -T file url then everything is ok the file gets uploaded. So either the way $http.put is working is bad (for this task) or curl has some magic. Can anyone elaborate?

2

There are 2 best solutions below

0
On BEST ANSWER

When uploading a file with the $http service, it is important to set Content-Type: undefined.

  var config = { headers: {
                   "Content-Type": undefined,
                  }
               };

  var promise = $http.put(url, file, config);

The default content type for the $http service is application/json. By setting Content-Type: undefined, the $http service omits the Content-Type header and the XHR API sets the Content-Type header to that of the file.

0
On

FYI:

I couldn't find out why $http is not working .. even I found strange things according to this topic.

So first I "fetched" the file from html like this:

<input flex="40" type="file" onchange="angular.element(this).scope().$parent.selectAttachment(this)">

becuase I didn't want to create a directive for this testing purpose. The selectAttachment function simply set the file as a property for my controller.

Then seemingly it was ok, I could read e.g this.attachment.name or this.attachment.size, but when I wrote $http.put(url, this.attachment) I got the signature-mismatch error.

Then I tried the same with XHR as in this tutorial: https://devcenter.heroku.com/articles/s3-upload-node

Never lucky...

Then, as a last resort, I tried to fetch the file by not setting it via angular but const file = document.getElementById('report-attachment').files[0]; and finally it worked for me. Intrestingly, fetching the file with getElementById AND using $http still not work, neither 1 or 2 3rd party angular uploader I tried, only with XHR o.o

The final "solution" which works for me:

HTML:

<input flex="40" id="report-attachment" type="file">

JS:

            const file = document.getElementById('report-attachment').files[0];
            const url = r && r.data;
            const xhr = new XMLHttpRequest();
            xhr.open('PUT', url);
            xhr.onreadystatechange = () => {
                if (xhr.readyState === 4) {
                    if (xhr.status === 200) {
                        console.debug('success');
                    } else {
                        console.error('error');
                    }
                }
            };
            xhr.send(file);