1

クライアント側の jQuery アップロード フォームを介して、Amazon にコンテンツ タイプを提供する方法を教えてください。コンテンツ タイプが適切に設定されていないと ie10 の jPlayer で再生されないオーディオ ファイルをアップロードしているため、コンテンツ タイプを追加する必要があります。私は pjambet によるブログ投稿 - http://pjambet.github.io/blog/direct-upload-to-s3/を使用して起動して実行しました (すばらしい投稿です)。ただし、フィールドの順序は非常に重要なようです。関連するコンテンツタイプ(オーディオ/ mpeg3だと思います)を含むか、アップロードスクリプトによって入力される空白の入力タグを挿入しようとしています。運がない。余分なフィールドが追加されると、アップロードがハングします。

直接アップロードフォーム.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
4

1 に答える 1

5

上記の質問のコメント セクションで述べたように、アップロードされたコンテンツの Content-Type を audio/mpeg3 に設定するには、2 つの変更が必要です。

  1. 追加の「Content-Type」値を受け入れるように、S3 POST API 呼び出しのポリシーを変更する必要があります。サンプル コードでは、s3_upload_policy_document メソッドの条件配列に次の条件を追加することでこれを実現できます。["eq", "$Content-Type", "audio/mpeg3"]

  2. 「Content-Type」変数は、S3 への POST リクエストに含める必要があります。jQuery ファイル アップローダ プラグインでは、S3 に送信されるフォームに、名前が「Content-Type」、値が「audio/mpeg3」の隠しフィールドを追加することで、これを実現できます。

于 2013-08-03T14:36:40.103 に答える