簡體   English   中英

使用Rails和jQuery文件上載將Content-Type設置為直接上傳到S3

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

我在這個主題上看到了很多問題,但是我遇到的任何問題對我都有用,所以我在這里發布另一個......

我正在Ruby on Rails上嘗試使用jQuery File Upload插件直接配置文件上傳到Amazon S3。 我跟着非常有用的Heroku教程來完成初始設置。 文件上傳很好,但在S3中它們都被標記為Content-Type: binary/octet-stream ,所以當它們在應用程序中提供時,所有文件都會下載而不是直接打開。

這是一個問題,因為我試圖允許圖像,PDF,音頻或視頻文件,所以我需要能夠從文件中獲取正確的Content-Type並將其傳遞給S3。 在查看亞馬遜上的AWS-SDK gem文檔時,我看到了本節有關將.where(:content_type).starts_with("")到預先簽名的post對象末尾以修改策略的內容。 但是,當我這樣做時,它引發了一個錯誤:

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

所以我將content_type: ""添加到預先簽名的post對象的opts哈希中,現在它再次起作用,但是所有文件默認為binary/octet-stream它們都默認為image/jpeg 這是我現在的代碼:

調節器

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?

用以下內容替換添加塊:

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

回調是正確的,但data.formData已經采用了原始版本的fd。 只需使用修改過的fd再次設置它就可以了。

更新控制器方法,所以你不要兩次:

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

如果有人正在尋找這個問題的更新答案,我能夠通過以下方式解決這個問題:

  1. 在我的s3預先發布的帖子中添加'內容類型以'開頭的條款,如本頁所述: http ://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-HTTPPOSTConstructPolicy.html
  2. 將名為“Content-Type”的隱藏輸入添加到我的表單,然后在選擇文件時相應地更新它。

我相信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