使用 Rails 和 jQuery File Upload 将 Content-Type 直接设置为 S3 上传 [英] Setting the Content-Type in direct to S3 upload using Rails and jQuery File Upload

查看:26
本文介绍了使用 Rails 和 jQuery File Upload 将 Content-Type 直接设置为 S3 上传的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在这里看到了很多关于这个主题的问题,但我遇到的没有一个对我有用,所以我在这里发布另一个......

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...

我在 Ruby on Rails 上尝试使用 jQuery 配置文件直接上传到 Amazon S3文件上传插件.我跟着非常有用的 Heroku 教程使初始设置工作.文件上传正常,但它们在 S3 中都被标记为 Content-Type: binary/octet-stream,因此当它们在应用程序中提供时,所有文件都会下载而不是直接打开.

I'm on Ruby on Rails trying to configure file uploads direct to Amazon S3 using the jQuery File Upload plugin. I followed along with the very helpful Heroku tutorial to get the initial setup working. 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.

这是一个问题,因为我试图允许图像、PDF、音频或视频文件,所以我需要能够从文件中获取正确的 Content-Type 并将其传递到 S3.在查看亚马逊上的 AWS-SDK gem 文档时,我看到了 本节 关于将 .where(:content_type).starts_with("") 添加到预签名帖子对象的末尾以修改策略.但是,当我这样做时,它抛出了一个错误:

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. 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. 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>

所以我将 content_type: "" 添加到预签名帖子对象的 opts 哈希中,现在它又可以工作了,但不是所有文件默认为 binary/octet-stream 它们都默认为 image/jpeg.这是我目前的代码:

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. Here's my code as of now:

控制器

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

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

如何将 Content-Type 正确发送到 S3?

How do I send the Content-Type properly to S3?

推荐答案

将添加块替换为:

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

回调是正确的,但是data.formData已经拿了fd的原版了.只需使用修改后的 fd 再次设置它,您就可以开始使用了.

The callback is correct, but data.formData already took the original version of fd. Just set it again with your modified fd and you should be good to go.

也要更新控制器方法,以免重复执行:

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("")

这篇关于使用 Rails 和 jQuery File Upload 将 Content-Type 直接设置为 S3 上传的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆