最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Uploading Base64 image data to S3 via AWS Ruby SDK - Stack Overflow

programmeradmin5浏览0评论

I've got a drag and drop function which takes the file that's been dropped on it and converts it to Base64 data. Before, it was uploading to Imgur, whose API supports Base64 uploads, and now I'm working on moving to Amazon S3.

I've seen examples of people using XMLHTTP requests and CORS to upload data to S3, I'm using Amazon's AWS S3 SDK gem to avoid having to sign policies and other things, as the gem does that for me. So what I've done is send the Base64 data to a local controller metod which uses the gem to upload to S3.

The other posts using Ajax i've seen show that S3 supports raw data uploads, but the gem doesn't seem to, as whenever I view the uploads i get broken images. Am I uploading it incorrectly? Is the data in the wrong format? I've tried the basic Base64, atob Base64, and blob urls, but nothing works so far.

JS:

fr.onload = function(event) {
        var Tresult = event.target.result;
        var datatype = Tresult.slice(Tresult.search(/\:/)+1,Tresult.search(/\;/));
        var blob = atob(Tresult.replace(/^data\:image\/\w+\;base64\,/, ''));
        $.ajax({
            type:"POST",
            data:{
                file:blob,
                contentType: datatype,
                extension:datatype.slice(datatype.search(/\//)+1)
            },
            url:'../uploads/images',
            success:function(msg) {
                handleStatus(msg,"success");
            },
            error:function(errormsg) {
                handleStatus(errormsg,"error");
            }
        });
    }

Controller method:

def supload
    s3 = AWS::S3.new(:access_key_id => ENV['S3_KEY'],:secret_access_key => ENV['S3_SECRET'])
    bucket = s3.buckets['bucket-name']
    data = params[:file].to_s
    type = params[:contentType].to_s
    extension = params[:extension].to_s
    name = ('a'..'z').to_a.shuffle[0..7].join + ".#{extension}"
    obj = bucket.objects.create(name,data,{content_type:type,acl:"public_read"})
    url = obj.public_url().to_s
    render text: url
end

Edit:

To be clear, I've tried a couple of different formats, the one displayed above is decoded base64. Regular Base64 looks like this:

        var Tresult = event.target.result;
        var datatype = Tresult.slice(Tresult.search(/\:/)+1,Tresult.search(/\;/));
        var blob = Tresult;
        $.ajax({
            type:"POST",
            data:{
                file:blob,
                mimeType: datatype,
                extension:datatype.slice(datatype.search(/\//)+1)
            },
            url:'../uploads/images',
            success:function(msg) {
                handleStatus(msg,"success");
            },
            error:function(errormsg) {
                handleStatus(errormsg,"error");
            }
        });

and a blob url looks like this:

var blob = URL.createObjectURL(dataURItoBlob(Tresut,datatype));
...
function dataURItoBlob(dataURI, dataType) {
    var binary = atob(dataURI.split(',')[1]);
    var array = [];
    for(var i = 0; i < binary.length; i++) {
        array.push(binary.charCodeAt(i));
    }
    return new Blob([new Uint8Array(array)], {type: dataType});
}

I've got a drag and drop function which takes the file that's been dropped on it and converts it to Base64 data. Before, it was uploading to Imgur, whose API supports Base64 uploads, and now I'm working on moving to Amazon S3.

I've seen examples of people using XMLHTTP requests and CORS to upload data to S3, I'm using Amazon's AWS S3 SDK gem to avoid having to sign policies and other things, as the gem does that for me. So what I've done is send the Base64 data to a local controller metod which uses the gem to upload to S3.

The other posts using Ajax i've seen show that S3 supports raw data uploads, but the gem doesn't seem to, as whenever I view the uploads i get broken images. Am I uploading it incorrectly? Is the data in the wrong format? I've tried the basic Base64, atob Base64, and blob urls, but nothing works so far.

JS:

fr.onload = function(event) {
        var Tresult = event.target.result;
        var datatype = Tresult.slice(Tresult.search(/\:/)+1,Tresult.search(/\;/));
        var blob = atob(Tresult.replace(/^data\:image\/\w+\;base64\,/, ''));
        $.ajax({
            type:"POST",
            data:{
                file:blob,
                contentType: datatype,
                extension:datatype.slice(datatype.search(/\//)+1)
            },
            url:'../uploads/images',
            success:function(msg) {
                handleStatus(msg,"success");
            },
            error:function(errormsg) {
                handleStatus(errormsg,"error");
            }
        });
    }

Controller method:

def supload
    s3 = AWS::S3.new(:access_key_id => ENV['S3_KEY'],:secret_access_key => ENV['S3_SECRET'])
    bucket = s3.buckets['bucket-name']
    data = params[:file].to_s
    type = params[:contentType].to_s
    extension = params[:extension].to_s
    name = ('a'..'z').to_a.shuffle[0..7].join + ".#{extension}"
    obj = bucket.objects.create(name,data,{content_type:type,acl:"public_read"})
    url = obj.public_url().to_s
    render text: url
end

Edit:

To be clear, I've tried a couple of different formats, the one displayed above is decoded base64. Regular Base64 looks like this:

        var Tresult = event.target.result;
        var datatype = Tresult.slice(Tresult.search(/\:/)+1,Tresult.search(/\;/));
        var blob = Tresult;
        $.ajax({
            type:"POST",
            data:{
                file:blob,
                mimeType: datatype,
                extension:datatype.slice(datatype.search(/\//)+1)
            },
            url:'../uploads/images',
            success:function(msg) {
                handleStatus(msg,"success");
            },
            error:function(errormsg) {
                handleStatus(errormsg,"error");
            }
        });

and a blob url looks like this:

var blob = URL.createObjectURL(dataURItoBlob(Tresut,datatype));
...
function dataURItoBlob(dataURI, dataType) {
    var binary = atob(dataURI.split(',')[1]);
    var array = [];
    for(var i = 0; i < binary.length; i++) {
        array.push(binary.charCodeAt(i));
    }
    return new Blob([new Uint8Array(array)], {type: dataType});
}
Share Improve this question edited May 23, 2017 at 10:31 CommunityBot 11 silver badge asked Jun 24, 2014 at 20:40 PolyovPolyov 2,3213 gold badges26 silver badges36 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 7

Am I reading this right that you are:

  1. Using AJAX to send a Base64-encoded file to Rails
  2. Using Rails to upload the file to S3
  3. Viewing the file in S3?

If that's the case, you need to decode the data in step 2 before sending it on to S3. Something like this might work:

require "base64"
def supload
    s3 = AWS::S3.new(:access_key_id => ENV['S3_KEY'],:secret_access_key => ENV['S3_SECRET'])
    bucket = s3.buckets['bucket-name']
    data = Base64.decode64(params[:file].to_s)
    type = params[:contentType].to_s
    extension = params[:extension].to_s
    name = ('a'..'z').to_a.shuffle[0..7].join + ".#{extension}"
    obj = bucket.objects.create(name,data,{content_type:type,acl:"public_read"})
    url = obj.public_url().to_s
    render text: url
end
发布评论

评论列表(0)

  1. 暂无评论