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

标签 jquery ruby-on-rails amazon-s3 content-type jquery-file-upload

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

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

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

<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。这是我现在的代码:

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

: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?

最佳答案

将添加 block 替换为:

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

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

也更新 Controller 方法,这样您就不会重复执行两次:

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

关于jquery - 使用 Rails 和 jQuery 文件上传直接将 Content-Type 设置为 S3 上传,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25315658/

相关文章:

ruby-on-rails - 编辑模型 - token URL

node.js - NodeJS foreach 没有返回正确的值

Python boto3 : receive versionId after uploading a file to S3

php - 使用 JavaScript 重定向到 PHP 脚本中的动态 href

javascript - 简单 'lazy loading'图像的正确方法

javascript - 如何比较没有年份的两个日期?只有月和日

jquery - Footable V3 Ajax数据加载: Error: No Columns Supplied

ruby-on-rails - 将电子邮件确认扩展到 Authlogic

ruby-on-rails - 如何将文本合并在一起?就像版本控制系统一样?

java - SPARK 驱动程序在读取多个 S3 文件时内存不足