Could not download image with s3 getSignedUrl('

2019-07-13 06:33发布

问题:

I'm relatively new to AWS. All I was trying to do is to upload image from my app to aws S3 and download it to view the image in another page in app. The upload was successful and was able to see the uploaded image in S3. But couldn't download it as it throws the following error.

     FileTransferError {body = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we
calculated does not match the signature you provided. Check your key and signing 
method.</Message><AWSAccessKeyId>AKXXXXXXXXXXXXXXXXXX</AWSAccessKeyId>
<StringToSign>GET\n\n\n1469897687\n/huntuploads/uploads/%25222a85a6675d15eeeca5c8b
da6eed4c52e%2522</StringToSign>
<SignatureProvided>cUBhtiA5AGJbj8vl%2FX6xi%2B9BBRY%3D</SignatureProvided>
<StringToSignBytes>47 45 54 0a 0a 0a 31 34 36 39 38 39 37 36 38 37 0a 2f 68 75 6e 
74 66 6f 6f 64 75 70 6c 6f 61 64 73 2f 75 70 6c 6f 61 64 73 2f 25 32 35 32 32 32 
61 38 35 61 36 36 37 35 64 31 35 65 65 65 63 61 35 63 38 62 64 61 36 65 65 64 34 
63 35 32 65 25 32 35 32 32</StringToSignBytes>
<RequestId>CCB513320456EB6B</RequestId>
<HostId>v4c7Ozf911tErWo5dCsL9RNLL78r3rUE6234Z801ZFXuELrji4juDehHmaxnK8t5qMBGcjz90a
I=</HostId></Error>";
        code = 3;
        "http_status" = 403;
        source = "https://huntuploads.s3-us-west-
2.amazonaws.com/uploads/%25222a85a6675d15eeeca5c8bda6eed4c52e%2522?
AWSAccessKeyId=AKXXXXXXXXXXXXXXXXXX&Expires=1469897687&Signature=cUBhtiA5AGJbj8vl%
252FX6xi%252B9BBRY%253D";
        target = "file:///var/mobile/Containers/Data/Application/1EB46B25-8BC5-
46C9-BE6B-BF1E120B7627/Documents/%222a85a6675d15eeeca5c8bda6eed4c52e%22";
}

Here is the following code for uploading the image which works fine at the server side

 var AWS = require('aws-sdk');
    AWS.config.update({accessKeyId: 'AXXXXXXXXX......', secretAccessKey: 'XXXXX....'});
    AWS.config.update({region: 'us-west-2'});

var s3 = new AWS.S3( { params: {Bucket: 'huntfooduploads'}});

app.post('/FileUpload', function(req, res, next) {
var fileStream = fs.createReadStream(req.files.file.path);
          var params = {
              'Key': 'uploads/' + req.files.file.name,
              'Body': fileStream,
              'ContentEncoding': 'base64',
              'Content-Type ': 'image/jpeg'
          };

   s3.upload(params, function(err, data) {
      if (err) throw err;
      console.log('after s3 upload====', err, data);
       var imgFileInfo = req.files;
       var imgUploadData = data;
       ....
   }
}

Here is the following code used for downloading the image using getSignedUrl for s3 from server side

var urlParams = {Bucket: 'huntuploads', Key:'uploads/'+rows[0].MyHunt_FileName};

  // s3 getSigned Url
  s3.getSignedUrl('getObject', urlParams, function(err, url)  {
      if (err) throw callback(err);
       var fullUrl={awsUrl:url};
       res.send(fullUrl);
  })

Once I send the fullUrl back to client side which is app, I tried using the following

$cordovaFileTransfer.download(encodeURI(itemData[3].awsUrl), targetPath, options, trustHosts)
         .then(function(result) {
           console.log('Success! Download is successful');
            $scope.imgURI = targetPath;
         }, function(err) {
            console.log('Error!!! Download is not successful');
           // Error
         }, function (progress) {
             $timeout(function () {
             $scope.downloadProgress = (progress.loaded / progress.total) * 100;
           });
         });

From the app side when I tried to download the image i get the message mentioned above. I tried with adding nx-amz-server-side-encryption-customer-algorithm:AES256 as a header. I need to know the following

  1. Is this the correct method of passing the data from server to client (app)
  2. If the urlParams for getSigned url is correct. Not sure if I'm missing something or anything to be done.

Can someone advise me in right direction.

回答1:

Well I've resolved my self. But thanks for your help Michael and others. The solution is I added the following line as options in one of the

var options = {encodeURI:false}; and then cordovaFileTransfer.download(encodeURI(itemData[3].awsUrl), targetPath, options, trustHosts){ ...}

which fixed the issue. Looks like encodeUI is set to true by default which changed the signature.



回答2:

As far as I know, getSignedUrl function does not check file exist,

1-Make sure your file URL is correct ( not signed URL).

2-Make sure permission and access to your bucket are correct

Finally, check you date and time of your machine when you call the getSignedUrl function.