XMLHttpRequest:以 XML 和图像作为负载的多部分/相关 POST [英] XMLHttpRequest: Multipart/Related POST with XML and image as payload

查看:14
本文介绍了XMLHttpRequest:以 XML 和图像作为负载的多部分/相关 POST的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从 Chrome 扩展程序中将图像(带有元数据)发布到 Picasa Webalbums.请注意,正如我在此处所描述的,带有 Content-Type image/xyz 的常规帖子有效.但是,我希望包含描述/关键字和 协议规范 描述了多部分/相关格式 带有 XML 和数据部分.

I'm trying to POST an image (with Metadata) to Picasa Webalbums from within a Chrome-Extension. Note that a regular post with Content-Type image/xyz works, as I described here. However, I wish to include a description/keywords and the protocol specification describes a multipart/related format with a XML and data part.

我通过 HTML5 FileReader 和用户文件输入获取数据.我检索了一个二进制文件使用

I'm getting the Data through HTML5 FileReader and user file input. I retrieve a binary String using

FileReader.readAsBinaryString(file);

假设这是 FileReader 加载字符串后的回调代码:

Assume this is my callback code once the FileReader has loaded the string:

function upload_to_album(binaryString, filetype, albumid) {

    var method = 'POST';
    var url = 'http://picasaweb.google.com/data/feed/api/user/default/albumid/' + albumid;
    var request = gen_multipart('Title', 'Description', binaryString, filetype);
    var xhr = new XMLHttpRequest();
    xhr.open(method, url, true);
    xhr.setRequestHeader("GData-Version", '3.0');
    xhr.setRequestHeader("Content-Type",  'multipart/related; boundary="END_OF_PART"');
    xhr.setRequestHeader("MIME-version", "1.0");
    // Add OAuth Token
    xhr.setRequestHeader("Authorization", oauth.getAuthorizationHeader(url, method, ''));
    xhr.onreadystatechange = function(data) {
        if (xhr.readyState == 4) {
            // .. handle response
        }
    };
    xhr.send(request);
}   

gen_multipart 函数只是根据输入值和 XML 模板生成多部分,并产生完全相同的输出 作为规范(除了..二进制图像数据..),但为了完整起见,这里是:

The gen_multipart function just generates the multipart from the input values and the XML template and produces the exact same output as the specification (apart from ..binary image data..), but for sake of completeness, here it is:

function gen_multipart(title, description, image, mimetype) {
    var multipart = ['Media multipart posting', "   
", '--END_OF_PART', "
",
    'Content-Type: application/atom+xml',"
","
",
    "<entry xmlns='http://www.w3.org/2005/Atom'>", '<title>', title, '</title>',
    '<summary>', description, '</summary>',
    '<category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/photos/2007#photo" />',
    '</entry>', "
", '--END_OF_PART', "
",
    'Content-Type:', mimetype, "

",
    image, "
", '--END_OF_PART--'];
    return multipart.join("");
}

问题是,POST 负载与原始图像数据不同,因此导致错误请求(Picasa 不会接受图像),尽管它在使用时运行良好

The problem is, that the POST payload differs from the raw image data, and thus leads to a Bad Request (Picasa won't accept the image), although it worked fine when using

xhr.send(file) // With content-type set to file.type

我的问题是,如何获得真实二进制图像以将其包含在多部分中?我认为它只是通过将它附加到 xml 字符串而被破坏,但我似乎无法修复它.

My question is, how do I get the real binary image to include it in the multipart? I assume it is mangled by just appending it to the xml string, but I can't seem to get it fixed.

请注意,由于 Picasa 中的旧错误,base64 不是解决方案.

Note that due to an old bug in Picasa, base64 is not the solution.

推荐答案

XMLHttpRequest 规范指出使用 .send() 方法发送的数据被转换为 unicode,并编码为 UTF-8.

The XMLHttpRequest specification states that the data send using the .send() method is converted to unicode, and encoded as UTF-8.

推荐的二进制数据上传方式是通过FormData API.但是,由于您不仅要上传文件,还要将二进制数据包装在 XML 中,因此该选项没有用处.

The recommended way to upload binary data is through FormData API. However, since you're not just uploading a file, but wrapping the binary data within XML, this option is not useful.

解决方法可以在的源代码中找到FormData for Web Workers Polyfill,我遇到类似问题时写的.为了防止 Unicode 转换,所有数据都被添加到一个数组中,最后作为一个 传输数组缓冲区.字节序列不涉及传输,每个规范.

The solution can be found in the source code of the FormData for Web Workers Polyfill, which I've written when I encountered a similar problem. To prevent the Unicode-conversion, all data is added to an array, and finally transmitted as an ArrayBuffer. The byte sequences are not touched on transmission, per specification.

下面的代码是一个特定的衍生,基于用于 Web Workers Polyfill 的 FormData:

The code below is a specific derivative, based on the FormData for Web Workers Polyfill:

function gen_multipart(title, description, image, mimetype) {
    var multipart = [ "..." ].join(''); // See question for the source
    var uint8array = new Uint8Array(multipart.length);
    for (var i=0; i<multipart.length; i++) {
        uint8array[i] = multipart.charCodeAt(i) & 0xff;
    }
    return uint8array.buffer; // <-- This is an ArrayBuffer object!
}

当您使用 .readAsArrayBuffer 而不是 .readAsBinaryString:

function gen_multipart(title, description, image, mimetype) {
    image = new Uint8Array(image); // Wrap in view to get data

    var before = ['Media ... ', 'Content-Type:', mimetype, "

"].join('');
    var after = '
--END_OF_PART--';
    var size = before.length + image.byteLength + after.length;
    var uint8array = new Uint8Array(size);
    var i = 0;

    // Append the string.
    for (; i<before.length; i++) {
        uint8array[i] = before.charCodeAt(i) & 0xff;
    }

    // Append the binary data.
    for (var j=0; j<image.byteLength; i++, j++) {
        uint8array[i] = image[j];
    }

    // Append the remaining string
    for (var j=0; j<after.length; i++, j++) {
        uint8array[i] = after.charCodeAt(j) & 0xff;
    }
    return uint8array.buffer; // <-- This is an ArrayBuffer object!
}

这篇关于XMLHttpRequest:以 XML 和图像作为负载的多部分/相关 POST的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆