如何正确地将对象上传到AWS S3?

时间:2015-06-10 23:54:33

标签: jquery ajax amazon-web-services amazon-s3

经过三天追逐这个问题。是时候寻求帮助了。 我有一个签名网址将文件上传到Amazon S3。我知道这是正确的,因为

curl -v -T file.png --header "Content-Type:binary/octet-stream" "https://sample.s3.amazonaws.com/33d7e8f0-0fc5-11e5-9d95-2b3410860edd?AWSAccessKeyId=XXXXXXXX&Content-Type=binary%2Foctet-stream&Expires=1433984735&Signature=LUjj8iIAbCfNoskGhqLDhuEWVG4%3D"

正确地成功。

但我的.ajax代码(如下)进行上传会使内容在S3存储桶中略微出现乱码 例如,如果我上传.pdf文件,它会从S3管理控制台正确加载,但如果它是.png或.jpeg等,则会失败...并且密切查看文件的长度(稍微)。

浏览器中呼叫的核心是:

var formData = new FormData();
formData.append("upload", file);
$.ajax({ url: data.puturl,
         type: 'PUT',
         xhr: function() {
           var myXhr = $.ajaxSettings.xhr();
           if (myXhr.upload) {
             myXhr.upload.addEventListener('progress', progressHandlingFunction, 
                                           false);
           }
           return myXhr;
         },
         success: completeHandler,
         error: errorHandler,
         data: formData,
         cache: $.param(false),
         contentType: "binary/octet-stream",
         processData: $.param(false)
         }, 'json');

这几乎似乎有效,但数据是乱码。我已经尝试将内容设置为file.type等无济于事。我需要在这里做一些编码吗?比如我失踪的base64 ????

非常感谢任何见解 或者,如果有一种简单的方法可以不使用.ajax做同样的事情,那就太好了。

1 个答案:

答案 0 :(得分:1)

从'tedder42'上面提到的问题以及更多实验中,我意识到发送FormData是个问题。所以我将代码更改为只使用FileReader()并传递原始数据。这非常有效。这是代码:

var reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = function (e) {
  var rawData = reader.result;
  $.ajax({ url: data.puturl,
    type: 'PUT',
    xhr: function() {
      var myXhr = $.ajaxSettings.xhr();
      if (myXhr.upload) {
        myXhr.upload.addEventListener('progress', progressHandlingFunction, false);
      }
      return myXhr;
    },
    success: completeHandler,
    error: errorHandler,
    // Form data
    data: rawData,
    cache: $.param(false),
    contentType: "binary/octet-stream",
    processData: $.param(false)
  }, 'json');
};

这更简单,一切都很完美。然后,当稍后使用签名的URL下载数据时,我只需输入

ResponseContentDisposition: "attachment; filename="+fileData.name

作为s3.getSignedUrl('getObject',params)调用中的一个参数。

在预先签名的URL中检索文件,我把

ResponseContentDisposition: "attachment; filename="+fileData.name, 'ResponseContentType': fileData.type 

负责确保浏览器期望接收的内容。

由于在使用预先签名的URL时上传对象时无法设置内容类型,因此我还在服务器端添加了代码,以便在上载完成后更改对象内容类型。这是代码的核心:

var params = {
  Bucket: 'sample',
  CopySource: 'sample/' + file.key,
  Key: file.key,
  MetadataDirective: 'REPLACE',
  ContentType: type
};
s3.copyObject(params, function (err, data){
  if (err) {
    console.log(err);
    validationError(res, 'unable to change content-type!');
  }
  res.sendStatus(200);
});

终于做对了这是一种痛苦,我希望这会有助于其他人!