简体   繁体   English

使用Rails和jQuery文件上载将Content-Type设置为直接上传到S3

[英]Setting the Content-Type in direct to S3 upload using Rails and jQuery File Upload

I've seen many questions here on this topic but nothing I've come across has worked for me, so here I am posting another... 我在这个主题上看到了很多问题,但是我遇到的任何问题对我都有用,所以我在这里发布另一个......

I'm on Ruby on Rails trying to configure file uploads direct to Amazon S3 using the jQuery File Upload plugin . 我正在Ruby on Rails上尝试使用jQuery File Upload插件直接配置文件上传到Amazon S3。 I followed along with the very helpful Heroku tutorial to get the initial setup working. 我跟着非常有用的Heroku教程来完成初始设置。 Files uploaded fine, but they were all labeled as Content-Type: binary/octet-stream in S3, so when they were served in the app, all files would download instead of opening directly. 文件上传很好,但在S3中它们都被标记为Content-Type: binary/octet-stream ,所以当它们在应用程序中提供时,所有文件都会下载而不是直接打开。

This is a problem because I'm trying to allow images, PDFs, audio or video files, so I need to be able to grab the correct Content-Type from the file and pass it on to S3. 这是一个问题,因为我试图允许图像,PDF,音频或视频文件,所以我需要能够从文件中获取正确的Content-Type并将其传递给S3。 In looking at the AWS-SDK gem docs on Amazon, I saw this section about adding .where(:content_type).starts_with("") to the end of the presigned post object to modify the policy. 在查看亚马逊上的AWS-SDK gem文档时,我看到了本节有关将.where(:content_type).starts_with("")到预先签名的post对象末尾以修改策略的内容。 However, when I did that, it threw an error: 但是,当我这样做时,它引发了一个错误:

<Error><Code>AccessDenied</Code>
<Message>Invalid according to Policy: Policy Condition failed: ["starts-with", "$Content-Type", ""]</Message>

So I added in content_type: "" into the opts hash for the presigned post object, and now it works again, but instead of all files defaulting to binary/octet-stream they all default to image/jpeg . 所以我将content_type: ""添加到预先签名的post对象的opts哈希中,现在它再次起作用,但是所有文件默认为binary/octet-stream它们都默认为image/jpeg Here's my code as of now: 这是我现在的代码:

Controller 调节器

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

_form.html.haml _form.html.haml

:javascript
  $(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  = $("<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({
        // This 'add' section is where I thought to set the Content-Type, but I've tried  with and without it and Content-Type remains the same on S3
        add: function (e, data) {
          fd["Content-Type"] = data.files[0].type;  
          console.log(fd);    // The JSON object shows Content-Type correctly in console
          data.submit();
        },  
        fileInput:        fileInput,
        url:              '#{@s3_direct_post.url}',
        type:             'POST',
        autoUpload:       true,
        formData:         fd,   // My updated JSON object
        paramName:        'file',
        dataType:         'XML',
        replaceFileInput: false,
        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   = 'https://d295xbrl26r3ll.cloudfront.net/' + key.replace(/ /g, "%20");

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

          progressBar.
            css("background", "red").
            text("Failed");
        }
      });
    });
  });

How do I send the Content-Type properly to S3? 如何将Content-Type正确发送到S3?

Replace your add block with: 用以下内容替换添加块:

      fd["Content-Type"] = data.files[0].type;  
      data.formData = fd;
      data.submit();

The callback is correct, but data.formData already took the original version of fd. 回调是正确的,但data.formData已经采用了原始版本的fd。 Just set it again with your modified fd and you should be good to go. 只需使用修改过的fd再次设置它就可以了。

Update the controller method too so you're not doing it twice: 更新控制器方法,所以你不要两次:

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

If anyone is looking for an updated answer to this question, I was able to solve this by: 如果有人正在寻找这个问题的更新答案,我能够通过以下方式解决这个问题:

  1. Adding a 'content type starts with' clause to my s3 presigned post, as documented on this page: http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-HTTPPOSTConstructPolicy.html 在我的s3预先发布的帖子中添加'内容类型以'开头的条款,如本页所述: http ://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-HTTPPOSTConstructPolicy.html
  2. Adding a hidden input named 'Content-Type' to my form and then updating it accordingly whenever a file is selected. 将名为“Content-Type”的隐藏输入添加到我的表单,然后在选择文件时相应地更新它。

I believe the most current syntax for aws-sdk (2.9.6) is: 我相信aws-sdk(2.9.6)的最新语法是:

@s3_direct_post = S3_BUCKET.presigned_post(
                  key: "uploads/#{SecureRandom.uuid}/${filename}",
                  success_action_status: 201,
                  acl: 'public-read',
                  content_type_starts_with: '')

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM