I am using ng-file-upload to upload a photo to S3. I have tested my S3 bucket and my policy/signature generator with the ng-file-upload demo tool and have successfully used it to upload the photo to my bucket.
Edit: A key difference seems to be the addition of a header:
Authorization:Token 3j4fl8jk0lqfkj4izj2w3ljfopljlwep1010notreal
That is present in my code but not in the demo page. Perhaps it's my angular app.
Installed through bower, took the relevant components, tried to upload a file, and get an error that looks like this:
400: <?xml version="1.0" encoding="UTF-8"?>
InvalidArgument
Unsupported Authorization Type
Authorization
Token 3j4fl8jk0lqfkj4izj2w3ljfopljlwep1010notreal
F1F5FK-not-real-81FED9CA
CQEW98p3D2e+pVz-not-real-codeu28m7asqpGjagL3409gj3f4kijKJpofk
Searching around, I've noted many 400 Errors but not many cases with the ArgumentValue as Token [some-code-here].
Looking at AWS documentation, InvalidArgument is a bit opaque for someone rather new to AWS.
And here is the policy that I'm encoding (Python):
#exptime = '2100-07-31T06:23:35Z' #for debugging
policy_document = {"expiration": exptime,
"conditions": [
{"bucket": settings.AWS_STORAGE_BUCKET_NAME},
["starts-with", '$key', ""],
{"acl": "private"},
["starts-with", "$Content-Type", ""],
["starts-with", "$filename", ""],
["content-length-range", 0, 5000000]
]
}
To reiterate, this policy with the aforementioned demo worked, so I expect a problem on my front-end implementation:
$scope.upload = function(file) {
file.upload = Upload.upload({
url: 'https://mybucket.s3-us-west-2.amazonaws.com',
method: 'POST',
fields: {
key: file.name,
AWSAccessKeyId: myAccessKeyId,
acl: 'private',
policy: myPolicyEncoded,
signature: mySignatureEncoded,
"Content-Type": file.type === null ||
file.type === '' ? 'application/octet-stream' : file.type,
filename: file.name
},
file: file
});
}
解决方案
Took me a while to find it, but as my edit pointed out, looking into the request header a token used in the Angular app's login/auth process was being sent as a default, and Amazon's service didn't like that. Removing the header in the http request for this specific case solved the issue.
The upload service on my front-end thus looks like:
$scope.upload = function(file) {
file.upload = Upload.upload({
url: 'https://mybucket.s3-us-west-2.amazonaws.com',
method: 'POST',
fields: {
key: file.name,
AWSAccessKeyId: myAccessKeyId,
acl: 'private',
policy: myPolicyEncoded,
signature: mySignatureEncoded,
"Content-Type": file.type === null ||
file.type === '' ? 'application/octet-stream' : file.type,
filename: file.name
},
headers: {
'Authorization': undefined
},
file: file
});
}