在将图像加载到aws s3时设置内容类型

时间:2015-08-23 04:49:52

标签: ruby-on-rails ruby ruby-on-rails-4 amazon-s3

我尝试将此heroku教程(https://devcenter.heroku.com/articles/direct-to-s3-image-uploads-in-rails)用于我的第一个应用。我花了一个星期的时间来研究这个复杂过程的细节,并且在这个过程中丢失了大部分剩余的头发。然而,在上传我的头像时设置内容类型的最后一点是剩下的。

我已尝试关注stackoverflow(Setting the Content-Type in direct to S3 upload using Rails and jQuery File Upload)上的帖子,在上传到aws之前设置文件的content_type但是当我尝试这样做时,我得到了403禁止错误。你能给些建议么。?在没有上述更改的情况下加载的默认内容类型是binary / octect-stream。

提供AWS.rb

AWS.config(access_key_id:     ENV['AWS_ACCESS_KEY_ID'],
secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'] )

S3_BUCKET = AWS::S3.new.buckets[ENV['S3_BUCKET']]

用户控制器具有预先签名的帖子 -

@s3_direct_post = S3_BUCKET.presigned_post(key: "uploads/#{SecureRandom.uuid}/${filename}", success_action_status: 201, acl: :public_read).where(:content_type).starts_with("") 

新用户表单中的脚本如下所示 -

                <script>
$(function() {
  $('.directUpload').find("input:file").each(function(i, elem) {
   var fileInput    = $(elem);
   var form         = $(fileInput.parents('form:first'));
   var submitButton = form.find('input[type="submit"]');
   var progressBar  = $("<br><div class='bar'></div>");
    var barContainer = $("<div class='progress'></div>").append(progressBar);
    var fd           = <%= @s3_direct_post.fields.to_json.html_safe %>;
   fileInput.after(barContainer);
   fileInput.fileupload({
   fileInput:       fileInput,
   url:             '<%= @s3_direct_post.url %>',
   type:            'POST',
   autoUpload:       true,
   formData:         fd,
   paramName:        'file', // S3 does not like nested name fields i.e.   name="user[avatar_url]"
   dataType:         'XML',  // S3 returns XML if success_action_status is set to 201
   replaceFileInput: false,
   limitMultiFileUploads: 1,
   maxFileSize: 999000,
   acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,

   progressall: function (e, data) {
     var progress = parseInt(data.loaded / data.total * 100, 10);
     progressBar.css('width', progress + '%')
   },
   start: function (e) {
     submitButton.prop('disabled', true);

     progressBar.css('background', 'green').css('display', 'block').
      css('width', '0%').
      text("Loading...");
    },

    done: function(e, data) {
     submitButton.prop('disabled', false);
     progressBar.text("Uploading done");

    // extract key and generate URL from response
     var key   = $(data.jqXHR.responseXML).find("Key").text();
     var url   = '//<%= @s3_direct_post.url.host %>/' + key;

    // create hidden field
    var input = $("<input />", { type:'hidden', name: fileInput.attr('name'), value: url })
    form.append(input);
  },
  fail: function(e, data) {
    submitButton.prop('disabled', false);

    progressBar.
      css("background", "red").
      text("Failed");
  },
   add: function (e, data) {
      fd["Content-Type"] = data.files[0].type;  
  data.formData = fd;
  data.submit();
    }


  });
 });
});

 </script> 

我还尝试过设置aws存储桶策略失败,但这没有帮助 -

{
"Statement": [
    {
        "Principal": "*",
        "Sid": "AllowPublicRead",
        "Action": [
            "s3:ListBucket",
            "s3:GetObject",
            "s3:PutObject",
            "s3:PutObjectAcl",
            "s3:DeleteObject"
        ],
        "Effect": "Allow",
        "Resource": [
            "arn:aws:s3:::bucket-name/*",
            "arn:aws:s3:::bcuket-name"
        ]
    }
]
}

任何指针都会有所帮助! TIA!

2 个答案:

答案 0 :(得分:0)

如果您获得403,则意味着POST请求被拒绝。您应该为您的存储桶启用POST。

目前你不允许发布POST。我通常使用CORS配置:

<CORSConfiguration>
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>POST</AllowedMethod>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>Authorization</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

您可能希望将原点更改为您自己的域,以防止来自其他来源的请求。

答案 1 :(得分:0)

对不起,不好意思。我想出了这个问题。对于遇到这篇文章的其他人来说,我在原帖中提供的代码应该按照没有存储桶策略的方式工作。我在测试的代码中添加了另一个:function(e,data){},并且正在进行其他文件类型检查,这是真正的罪魁祸首。

Michael - 内容类型正在添加:回调函数。

Lukasz Muzyka - 我的CORS设置相同......

非常感谢你的帮助!