简体   繁体   中英

Setting file content-type in S3 with jQuery file upload

I need help providing a content-type to amazon via a client side jQuery upload form. I need to add the content type because I'm uploading audio files that will not play in jPlayer for ie10 unless the content type is properly set. I used the blog post by pjambet - http://pjambet.github.io/blog/direct-upload-to-s3/ to get up and running (excellent post btw). It seems though that the order of the fields is extremely important. I've been trying to insert a hidden input tag either contaning the relevant content type (audio/mpeg3 I think) or blank to be populated by my upload script. No luck. The upload hangs when the extra fields are added.

direct-upload-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>

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

As mentioned in the comments section for the above question, two changes are required to set the Content-Type for the uploaded content to audio/mpeg3.

  1. The policy for the S3 POST API call must be changed to accept an additional "Content-Type" value. In the sample code, this can be achieved by adding the following condition to the conditions array in the s3_upload_policy_document method: ["eq", "$Content-Type", "audio/mpeg3"]

  2. The "Content-Type" variable must be included with the POST request to S3. In the jQuery file uploader plugin this can be achieved by adding a hidden field to the form that is sent to S3, with the name "Content-Type" and the value "audio/mpeg3".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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