在我开始之前:这是一个100%的客户端问题。忘记服务器端语言,如何处理上传等等,我正在将一个已知的有效HTTP文件上传请求与一个jQuery生成的AJAX请求进行比较,该请求在理论上应该做同样的事情。

背景:我正在为tinyMCE写一个文件上传插件。其中一部分涉及允许支持它的浏览器拖放图像-特别是,当文件系统图像放入tinyMCE编辑器时,firefox中的tinyMCE使用base64 src创建img。这是我当前的用例,以后可能会扩展。

我的目标是获取base64数据,并使用jQuery模拟表单提交以将其上传到服务器。我已经有一种正常的基于HTML表单的方法可以正常工作。

获取base64数据很容易:

$('img[src^="data:"]', ed.getDoc()).each(function(){
    var data = /data:(image\/\w+);base64,(.*)/gmi.exec(this.src), format, ext;
    if (data){
        format = data[1];
        ext = format.split('/')[1];
        data = atob(data[2]);
    }
    else{
        // blah, not supported
    }
});


准备POST数据同样容易:

var boundary = '--------------------boundary' + (new Date).getTime();
data = '\r\n' + boundary + '\r\n' +
        'Content-Disposition: form-data; name="file-upload"; filename="uploaded_image.' + ext + '"\r\n' +
        'Content-Type: ' + format + '\r\n\r\n' +
        data + '\r\n' +
        boundary + '--'
        ;


剩下的就是将其发送到服务器:

$.ajax({
    type: 'POST',
    url: '/upload/',
    contentType: 'multipart/form-data; boundary=' + boundary.slice(2),
    data: data
});


服务器“正确地”处理了POST(它可以正确地看到文件并将其保存到磁盘中),但是生成的图像已被损坏-它不会在浏览器中显示,并且其jpeg header是完全错误的,不是更不用说它比本地大33%(服务器上为12K,本地为9K)。

使用Firebug的[Net]选项卡,一切看起来都没错-实际上,除了Content-Type请求标头中的额外charset=UTF-8以及缺少漂亮打印的POST数据外,此AJAX请求看起来与相应的POST形式完全相同。但是,使用HttpFox可以讲述一个不同的故事:

表格上传:

-----------------------------191891488320550623041315726177
Content-Disposition: form-data; name="file-upload"; filename="file.jpg"
Content-Type: image/jpeg

ÿØÿàJFIFHHÿÛC...


ajax上传:

--------------------boundary1375846064929
Content-Disposition: form-data; name="file-upload"; filename="file.jpeg"
Content-Type: image/jpeg

ÿÃÿà JFIFHHÿÃC...


我还注意到请求的Content-Length值又相差33%。如此看来,无论出于何种原因,jQuery生成的POST请求实际上都不会以UTF-8发送?我想念的是什么,这个难题的最后一部分是什么?

最佳答案

事实证明,该解决方案是使用Typed Arrays和XHR2的FormData(polyfills都可使用,但目前都具有强大的本机支持)。

images.each(function(){
    var image = this,
        data = /data:(image\/\w+);base64,(.*)/gmi.exec(this.src),
        format, ext, binary;
    if (data){
        format = data[1];
        ext = format.split('/')[1];
        binary = atob(data[2]);
        data = new Uint8Array(binary.length);
        for (var i=0; i<binary.length; i++)
            data[i] = binary.charCodeAt(i);
    }
    else {
        // blah, not supported
    }

    var fd = new FormData();
    fd.append('file-upload', new Blob([data], {type: format}), 'uploaded_image.' + ext);

    $.ajax({
        type: 'POST',
        url: '/upload/',
        data: fd,
        processData: false,
        contentType: false
    });
});

09-30 18:59
查看更多