简体   繁体   中英

jQuery.ajax emulating POST file upload, not sending UTF-8 content

Before I start: This is a 100% client-side question. Forget the server side language, how I handle the uploads, etc -- I'm comparing a known working HTTP file upload request with a jQuery-generated AJAX request that theoretically should be doing the same thing.

Background: I'm writing a file upload plugin for tinyMCE. Part of this involves allowing drag-and-drop image uploading for browsers that support it -- specifically, tinyMCE in firefox creates an img with a base64 src when a filesystem image is dropped into the tinyMCE editor. That's my current use case, it may be expanded later.

My goal is to take the base64 data and use jQuery to emulate a form submission to upload it to the server. I already have a normal HTML form-based approach that is working.

Getting the base64 data is cake:

$('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
    }
});

Prepping the POST data similarly easy:

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 + '--'
        ;

All that's left is to send it off to the server:

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

The server handles the POST "correctly" (it sees the file and saves it to disk just fine), but the resulting image is quite corrupted -- it won't display in a browser, and its jpeg header is completely wrong, not to mention it's about 33% larger than it is locally (12K on the server vs 9K local).

Using Firebug's Net tab, nothing looks wrong -- in fact, apart from an extra charset=UTF-8 in the Content-Type request header and the lack of pretty-printing POST data, this AJAX request looks exactly like the corresponding form POST. Using HttpFox , though, tells a different story:

form upload:

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

ÿØÿàJFIFHHÿÛC...

ajax upload:

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

ÿÃÿà JFIFHHÿÃC...

I also notice that the request Content-Length values are different, again by about 33%. So it seems that, for whatever reason, jQuery-generated POST requests don't actually get sent in UTF-8? What am I missing, what's the final piece of this puzzle?

The solution turned out to be to use Typed Arrays and XHR2's FormData (polyfills are available for both, but both currently enjoy significant native support).

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
    });
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM