简体   繁体   English

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

[英]How to properly upload an object to AWS S3?

After three days of chasing this problem. 经过三天的追逐这个问题。 It's time to ask for some help. 是时候寻求帮助了。 I have a signed url to upload a file to Amazon S3. 我有一个签名的URL,可以将文件上传到Amazon S3。 I know this is correct, since a 我知道这是正确的,因为

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"

succeeds correctely. 正确地成​​功。

But my .ajax code (below) which does the upload leaves the content garbled slightly in the S3 bucket. 但是我执行上载的.ajax代码(如下)使内容在S3存储桶中略有乱码。
For example if I upload a .pdf file, it loads properly from the S3 Management Console, but if it is a .png or .jpeg, etc. it fails... And looking closely the file has the wrong length (slightly). 例如,如果我上传一个.pdf文件,则可以从S3管理控制台正确加载该文件,但是如果它是.png或.jpeg等文件,则失败...并且仔细查看该文件的长度(略有错误)。

The heart of the call in the browser is: 浏览器中调用的核心是:

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');

This almost seems to work, but the data is garbled. 这似乎几乎可以正常工作,但是数据出现乱码。 I have tried setting the content to file.type, etc. to no avail. 我尝试将内容设置为file.type等,但无济于事。 Is there some encoding that I need to do here? 我在这里需要做一些编码吗? Such as base64 that I am missing???? 如我所缺少的base64 ????

Any insight would be greatly appreciated. 任何见识将不胜感激。
OR if there is an easy way to not use .ajax to do the same thing, that would be great. 或者,如果有一种简单的方法可以不使用.ajax来执行相同的操作,那将是很好的。

From the question that 'tedder42' asked above, and some more experimentation, I realized that sending the FormData was the issue. 根据上面“ tedder42”提出的问题以及更多的实验,我意识到发送FormData是问题。 So I changed the code to just use a FileReader() and pass the raw data. 因此,我将代码更改为仅使用FileReader()并传递原始数据。 This works perfectly. 这很完美。 Here is the code: 这是代码:

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');
};

This is much more straightforward and everything works perfectly. 这要简单得多,并且一切都可以完美运行。 Then when the data is downloaded later using a signed url, I simply put 然后,当稍后使用签名的URL下载数据时,我只需输入

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

as one of the params in the s3.getSignedUrl('getObject', params) call. 作为s3.getSignedUrl('getObject',params)调用中的参数之一。

AND in the presigned url to retrieve the file, I put 我在预先签名的网址中输入AND来检索文件

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

which takes care of ensuring that the browser expects what it is receiving. 这样可以确保浏览器期望收到的内容。

Because you cannot set the content-type when uploading the object when using a pre-signed url, I also added code on the server side to change the object content-type after the upload has completed. 因为在使用预签名的url时上传对象时无法设置内容类型,所以我还在服务器端添加了代码,以在上传完成后更改对象的内容类型。 Here is the heart of the code: 这是代码的核心:

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);
});

This was a pain to finally get right and I am hopeful that this will help others! 最终要正确做这是一个痛苦,我希望这将对其他人有所帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在Rails中使用Ajax和Jquery将图像上传到Amazon AWS(S3)? - How to upload an Image to Amazon AWS (S3) using Ajax and Jquery in Rails? 使用预签名 URL 将文件上传到 AWS S3 - Upload file to AWS S3 using Pre-Signed URL 使用Meteor,jQuery和AWS开发工具包将浏览器直接上传到S3 - Direct Browser Upload to S3 with Meteor, jQuery and the AWS SDK AWS-CORS无法将文件直接上传到S3 - AWS - CORS not working to upload file directly to S3 在遵循Heroku关于如何直接上传到AWS S3的教程之后,无法将ActionDispatch :: Http :: UploadedFile转换为字符串 - can't cast ActionDispatch::Http::UploadedFile to string after following Heroku's tutorial on how to upload directly to aws s3 如何将InMemoryUploadedFile上传到我的S3 Bucket? - How to upload InMemoryUploadedFile to my S3 Bucket? Rails使用aws-sdk gem和heroku上的jQuery-File-Upload直接进入S3上传 - Rails direct to S3 upload using aws-sdk gem and jQuery-File-Upload on heroku AWS S3文件上传,没有出现“访问控制允许来源”错误 - AWS S3 File Upload, getting No 'Access-Control-Allow-Origin' error Presigned AWS S3 PUT url无法使用jquery从客户端上传 - Presigned AWS S3 PUT url fails to upload from client using jquery 将图像上传到Amazon S3(如何获取签名和策略文档) - Upload Image to Amazon S3 (How to get Signature and Policy Doc)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM