使用Ajax上传Base64图像

29

我的客户希望用户选择一张图片,进行剪裁和调整大小,然后展示它(在一个 <img> DOM 元素中)。

如果图片没问题,用户可以将其上传到服务器以便保存。

我想要通过Ajax请求来完成上传。

我在互联网上找到了很多例子,用于上传从客户端PC获取的原始图片。例如:

$( '#my-form' )
  .submit( function( e ) {
    $.ajax( {
      url: 'http://host.com/action/',
      type: 'POST',
      data: new FormData( this ),
      processData: false,
      contentType: false
    } );
    e.preventDefault();
  } );

如果我决定上传通过表单输入检索到的图片,则这将正常工作。

在我的情况下,我想要上传被修改后的图片(保存在<img>元素中),而不是原始图片。
此图片以base64格式存储(供参考:我使用croppie.js库生成图像)。

我不知道如何使用Ajax上传这张图片。

我尝试将其作为普通参数上传,但服务器端的img为空字符串:

var url = 'http://host.com/action/';
var data = {};
data.img = $('img#generated-image').attr('src');

$.ajax({url: url, type: "POST", data: data})
  .done(function(e){
    // Do something
  });
// RESULTS in a empty data.img on the server side.

我的问题是在检索"img"参数时,服务器收到一个空字符串。我怀疑是图片可能太大而无法传递给服务器,或者其他我不理解的问题...。

所以我想知道使用Ajax请求发送base64图像到服务器的正确方法而不使用表单

感谢您的帮助。

编辑

似乎是xmlHTTP POST参数大小的问题。我试图减少图像的字符串表示中的字符数,现在服务器能够检索它。

编辑2

在php.ini文件中,post_max_size设置为8M,而图片大小只有24K。因此问题不在那里。
我正在使用带有Symfony2框架的PHP。
可能是Symfony2的限制。


你使用什么样的服务器来解析这些请求?限制可能存在于服务器端,而不是客户端。 - Jeremy
1
@JeremyBanks:我正在使用Symfony2框架的PHP。我检查了php.ini中的post_max_size,它设置为8M。图片只有24K大小。所以也许是Symfony限制了最大尺寸。到目前为止,我还没有找到任何相关的信息...。 - Nitseg
2个回答

55

我最终决定将base64图像转换为Blob,以便可以通过formData对象通过Ajax请求发送,如下所示。这样可以节省上传带宽(base64比其二进制等效物多占用33%的比特),而且我找不到不传输base64参数的原因(肯定是由于某个地方的大小限制)。

base64ToBlob函数基于另一个问题的这个答案

function base64ToBlob(base64, mime) 
{
    mime = mime || '';
    var sliceSize = 1024;
    var byteChars = window.atob(base64);
    var byteArrays = [];

    for (var offset = 0, len = byteChars.length; offset < len; offset += sliceSize) {
        var slice = byteChars.slice(offset, offset + sliceSize);

        var byteNumbers = new Array(slice.length);
        for (var i = 0; i < slice.length; i++) {
            byteNumbers[i] = slice.charCodeAt(i);
        }

        var byteArray = new Uint8Array(byteNumbers);

        byteArrays.push(byteArray);
    }

    return new Blob(byteArrays, {type: mime});
}

我的 JS 代码:

var url = "url/action";                
var image = $('#image-id').attr('src');
var base64ImageContent = image.replace(/^data:image\/(png|jpg);base64,/, "");
var blob = base64ToBlob(base64ImageContent, 'image/png');                
var formData = new FormData();
formData.append('picture', blob);

$.ajax({
    url: url, 
    type: "POST", 
    cache: false,
    contentType: false,
    processData: false,
    data: formData})
        .done(function(e){
            alert('done!');
        });

在Symfony2中,我可以通过以下方式检索图像:

$picture = $request->files->get('picture');

3
有趣的是,你找到的那段代码似乎大部分来自于我的回答,只是更改了一些变量名并将其包装为用于Node模块。我喜欢他在版权上放上自己的名字,而按行计数,这实际上更多是我的代码而不是他的。也许我应该起诉他。 ;) 我将更改你帖子中的链接,指向我的回答。 - Jeremy
4
是的,我看到了几个非常相似的base64ToBlob函数版本,还有一些其他函数几乎做了相同的事情。 很高兴找到了根源作者。 :-) 谢谢你的帮助。 - Nitseg
45
这个网站上所有发布的代码都像创意共用许可证之类的吗?如果你对别人复制你的代码感到不满,我认为最好不要公开发布它。这是我的建议。 - Coty Embry
1
@CotyEmbry 我认为Jeremy生气了,因为抄袭他代码的人在上面加了版权标志,而那份代码不是由他编写的,只是重新使用了他的代码 :) - Andrea Gobetti

3
Nitseg的答案很好用。如果你必须在ajax调用中使用auth token,我还想添加以下几行代码。同样,请先查看Nitseg的答案以获取更多详细信息。
var formData = new FormData();
var token = "<YOUR-TOKEN-HERE>";
formData.append("uploadfile", mediaBlob);        

jQuery.ajax({
    url: url,
    type: "POST",
    cache: false,
    contentType: false,
    processData: false,
    data: formData,
    beforeSend: function (xhr){ 
        xhr.setRequestHeader("Authorization", "Bearer " + token); 
    }
})
.done((e) => {
    // It is done.
})
.fail((e) => {
    // Report that there is a problem!
}); 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接