【问题标题】:Setting file content-type in S3 with jQuery file upload使用 jQuery 文件上传在 S3 中设置文件内容类型
【发布时间】:2013-08-02 13:29:13
【问题描述】:

我需要通过客户端 jQuery 上传表单向亚马逊提供内容类型的帮助。我需要添加内容类型,因为我上传的音频文件不会在 ie10 的 jPlayer 中播放,除非正确设置了内容类型。我使用 pjambet 的博客文章 - http://pjambet.github.io/blog/direct-upload-to-s3/ 启动并运行(顺便说一句,出色的帖子)。尽管字段的顺序似乎非常重要。我一直在尝试插入包含相关内容类型(我认为是音频/mpeg3)的隐藏输入标签,或者插入空白以由我的上传脚本填充。没有运气。添加额外字段时,上传会挂起。

直接上传-form.html.erb

<form accept-charset="UTF-8" action="http://my_bucket.s3.amazonaws.com" class="direct-upload" enctype="multipart/form-data" method="post"><div style="margin:0;padding:0;display:inline"></div>

    <%= hidden_field_tag :key, "${filename}" %>
    <%= hidden_field_tag "AWSAccessKeyId", ENV['AWS_ACCESS_KEY_ID'] %>
    <%= hidden_field_tag :acl, 'public-read' %>
    <%= hidden_field_tag :policy %>
    <%= hidden_field_tag :signature %>
    <%= hidden_field_tag :success_action_status, "201" %>
    <%= file_field_tag :file %>

    <div class="row-fluid">
        <div class="progress hide span8">
            <div class="bar"></div>
        </div>
    </div>

</form>

音频上传.js

$(function() {
  $('input[type="submit"]').attr("disabled","true");
  $('input[type="submit"]').val("Please upload audio first");

  if($('#demo_audio').val() != ''){
    var filename = $('#demo_audio').val().split('/').pop().split('%2F').pop();
    $('#file_status').removeClass('label-info').addClass('label-success').html(filename + ' upload complete');
  }

  $('.direct-upload').each(function() {    
    var form = $(this)

    $(this).fileupload({
      url: form.attr('action'),
      type: 'POST',
      autoUpload: true,
      dataType: 'xml', // This is really important as s3 gives us back the url of the file in a XML document
      add: function (event, data) {
        $.ajax({
          url: "/signed_urls",
          type: 'GET',
          dataType: 'json',
          data: {doc: {title: data.files[0].name}}, // send the file name to the server so it can generate the key param
          async: false,
          success: function(data) {
            // Now that we have our data, we update the form so it contains all
            // the needed data to sign the request
            form.find('input[name=key]').val(data.key)
            form.find('input[name=policy]').val(data.policy)
            form.find('input[name=signature]').val(data.signature)            
          }
        })
        data.form.find('#content-type').val(file.type)
        data.submit();
      },
      send: function(e, data) {
        var filename = data.files[0].name;
        $('input[type="submit"]').val("Please wait until audio uploaded is complete..."); 
        $('#file_status').addClass('label-info').html('Uploading ' + filename);
        $('.progress').fadeIn();        
      },
      progress: function(e, data){
        // This is what makes everything really cool, thanks to that callback
        // you can now update the progress bar based on the upload progress
        var percent = Math.round((e.loaded / e.total) * 100)
        $('.bar').css('width', percent + '%')
      },
      fail: function(e, data) {
        console.log('fail')
      },
      success: function(data) {
        // Here we get the file url on s3 in an xml doc
        var url = $(data).find('Location').text()

        $('#demo_audio').val(url) // Update the real input in the other form
      },
      done: function (event, data) {
        $('input[type="submit"]').val("Create Demo");
        $('input[type="submit"]').removeAttr("disabled"); 
        $('.progress').fadeOut(300, function() {
          $('.bar').css('width', 0);
          var filename = data.files[0].name;
          $('span.filename').html(filename);     
          $('#file_status').removeClass('label-info').addClass('label-success').html(filename + ' upload complete');
          $('#file').hide();
        })
      },

    })
  })
})

signed_urls_controller.rb

class SignedUrlsController < ApplicationController
  def index
    render json: {
      policy: s3_upload_policy_document,
      signature: s3_upload_signature,
      key: "uploads/#{SecureRandom.uuid}/#{params[:doc][:title]}",
      success_action_redirect: "/"
    }
  end

  private

  # generate the policy document that amazon is expecting.
  def s3_upload_policy_document
    Base64.encode64(
      {
        expiration: 30.minutes.from_now.utc.strftime('%Y-%m-%dT%H:%M:%S.000Z'),
        conditions: [
          { bucket: ENV['AWS_S3_BUCKET'] },
          { acl: 'public-read' },
          ["starts-with", "$key", "uploads/"],
          { success_action_status: '201' }
        ]
      }.to_json
    ).gsub(/\n|\r/, '')
  end

  # sign our request by Base64 encoding the policy document.
  def s3_upload_signature
    Base64.encode64(
      OpenSSL::HMAC.digest(
        OpenSSL::Digest::Digest.new('sha1'),
        ENV['AWS_SECRET_ACCESS_KEY'],
        s3_upload_policy_document
      )
    ).gsub(/\n/, '')
  end
end

【问题讨论】:

  • 向表单添加一个名为“Content-Type”的隐藏输入和一个与文件的 MIME 类型匹配的值应该可以工作,但您还需要修改策略(您的 /signed_urls 脚本) S3 接受您的请求。最好使用 Fiddler 或 Charles 等网络调试工具调查发送到 S3 的实际请求和响应,以便更好地了解正在发生的事情。
  • 有趣,我从没想过要更新它。我显然需要在 S3 上做更多的功课。我在我的问题中添加了返回签名的控制器的代码。那么在该控制器的 s3_upload_policy_document 方法中,将新字段添加到条件数组中?
  • 是的,在条件数组中添加类似 ["eq", "$Content-Type", "audio/mpeg3"] 的内容。当 S3 停止响应“根据策略无效:...”之类的内容时,您就会知道自己做对了。
  • 非常感谢@dcro,成功了。并且在上传时设置内容类型使音频可以在生产中播放! :) 如果您将您的评论变成答案,我很乐意接受。
  • 不客气,我很高兴你能够让它工作。我已经添加了上面的信息作为答案。

标签: ruby-on-rails amazon-s3 jquery-file-upload


【解决方案1】:

如上述问题的 cmets 部分所述,需要进行两项更改才能将上传内容的 Content-Type 设置为 audio/mpeg3。

  1. 必须更改 S3 POST API 调用的策略以接受额外的“Content-Type”值。在示例代码中,这可以通过在 s3_upload_policy_document 方法中的条件数组中添加以下条件来实现:["eq", "$Content-Type", "audio/mpeg3"]

  2. “Content-Type”变量必须包含在对 S3 的 POST 请求中。在 jQuery 文件上传器插件中,这可以通过在发送到 S3 的表单中添加一个隐藏字段来实现,其名称为“Content-Type”,值为“audio/mpeg3”。

【讨论】:

  • 内容类型未知怎么办?例如,假设您要上传具有不同内容类型的多个文件?
  • @Mohamad 您可以在策略中使用此条件:["starts-with", "$Content-Type", ""],它将接受任何内容类型。
  • 是的,我终于在文档中找到了。我使用的是 AWS gem,它将键映射到与在策略中设置不同的值。大写导致政策错误并让我失望。
猜你喜欢
  • 2012-07-22
  • 2014-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多