問題描述
我正在嘗試從 Chrome 擴(kuò)展程序中將圖像(帶有元數(shù)據(jù))發(fā)布到 Picasa 網(wǎng)絡(luò)相冊(cè).請(qǐng)注意,正如我在此處所述,使用 Content-Type image/xyz 的常規(guī)帖子有效.但是,我希望包含描述/關(guān)鍵字和 協(xié)議規(guī)范 描述了 multipart/related 格式 帶有 XML 和數(shù)據(jù)部分.
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 和用戶文件輸入獲取數(shù)據(jù).我檢索一個(gè)二進(jìn)制文件使用
I'm getting the Data through HTML5 FileReader and user file input. I retrieve a binary String using
FileReader.readAsBinaryString(file);
假設(shè)這是我在 FileReader 加載字符串后的回調(diào)代碼:
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 函數(shù)只是從輸入值和 XML 模板生成多部分,并產(chǎn)生完全相同的輸出 作為規(guī)范(除了..二進(jìn)制圖像數(shù)據(jù)..),但為了完整起見,這里是:
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 有效負(fù)載與原始圖像數(shù)據(jù)不同,因此會(huì)導(dǎo)致錯(cuò)誤請(qǐng)求(Picasa 不會(huì)接受圖像),盡管在使用時(shí)它工作正常
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
我的問題是,如何讓 real 二進(jìn)制圖像包含在多部分中?我認(rèn)為它只是通過將它附加到 xml 字符串而被破壞,但我似乎無法修復(fù)它.
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.
請(qǐng)注意,由于 Picasa 中存在 舊錯(cuò)誤,base64 不是解決方案.
Note that due to an old bug in Picasa, base64 is not the solution.
推薦答案
XMLHttpRequest 規(guī)范 聲明使用 .send()
方法發(fā)送的數(shù)據(jù)將轉(zhuǎn)換為 unicode,并編碼為 UTF-8.
The XMLHttpRequest specification states that the data send using the .send()
method is converted to unicode, and encoded as UTF-8.
推薦的二進(jìn)制數(shù)據(jù)上傳方式是通過FormData
API.但是,由于您不只是上傳文件,而是將二進(jìn)制數(shù)據(jù)包裝在 XML 中,因此此選項(xiàng)沒有用.
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,這是我遇到類似問題時(shí)寫的.為了防止 Unicode 轉(zhuǎn)換,所有數(shù)據(jù)都添加到一個(gè)數(shù)組中,最后作為 傳輸數(shù)組緩沖區(qū)
.根據(jù)規(guī)范,字節(jié)序列在傳輸時(shí)不會(huì)被觸及.
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:
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!
}
當(dāng)您使用 .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!
}
這篇關(guān)于XMLHttpRequest:以 XML 和圖像作為有效負(fù)載的多部分/相關(guān) POST的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,也希望大家多多支持html5模板網(wǎng)!