我需要通过客户端 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