Javascript XMLHttpRequest 中表单数据的二进制字符串连接
Javascript binary string concatenation on form-data in XMLHttpRequest
我正在编写一个 Chrome 扩展,需要构建自定义表单数据以将 Zip 文件(我不能使用真正的 HTML 表单)上传到服务器(不是矿)。
我在这里找到了一种方法 -
https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Forms/Sending_forms_through_JavaScript(最后一节 - 处理二进制数据)。
它可以很好地处理明文文件,但我想发送二进制的 Zip。
似乎 JavaScript 无法处理二进制和非二进制的连接,并在我的文件中添加了一些 0Xc2 字符)-:
我也在 http://footle.org/2007/07/31/binary-multipart-posts-in-javascript/ 找到了解决方案,
但它使用 Components.classes["@mozilla.org/io/string-input-stream;1"]
,这在 Chrome 扩展中不可用。
如何将二进制 zip 文件与字符串连接起来并将其上传到服务器?
function sendData(zipBinary) {
var XHR = new XMLHttpRequest();
var boundary = "----WebKitFormBoundary3n9vu9ZOkCPW4HAw";
var prefix = "";
var postfix = "";
prefix += "--" + boundary + "\r\n";
prefix += 'content-disposition: form-data; '
+ 'name="' + 'UploadedFile' + '"; '
+ 'filename="' + 'hello.zip' + '"\r\n';
prefix += 'Content-Type: ' + 'application/x-zip-compressed' + '\r\n';
prefix += '\r\n';
postfix += '\r\n';
// Once we are done, we "close" the body's request
postfix += "--" + boundary + "--";
postfix += '\r\n';
XHR.addEventListener('load', function(event) {
alert('Yeah! Data sent and response loaded.');
});
XHR.addEventListener('error', function(event) {
alert('Oups! Something goes wrong.');
});
XHR.open('POST', 'https://example.com');
XHR.setRequestHeader('Content-Type','multipart/form-data; boundary=' + boundary);
XHR.send(prefix + zipBinary + postfix); // <----
}
您是否阅读了所链接文章中的 section about FormData?因为这是通过 XMLHttpRequest API 发送文件的最佳解决方案。这种 API 优于字符串连接的优点是文件可以以流方式上传,而不必在发送前完全缓冲在内存中。
假设zipBinary
是一个Blob
或File
对象,你可以上传一个文件如下:
function sendData(zipBinary) {
var xhr = new XMLHttpRequest();
var fd = new Formdata();
fd.append('hello.zip', zipBinary);
xhr.onload = function() {
// Request completed! Use xhr.status and/or xhr.responseText to
// check the server's response status code and response body.
};
xhr.onerror = function() {
// Aw. Network error.
};
xhr.open('POST', 'https://example.com/');
xhr.send(fd);
}
如果zipBinary
不是Blob or File对象,而是一串二进制数据,那么您可以将其转换为具有指定MIME-type的Blob,如下所示:
function sendData(zipBinary) {
var zipBinaryBytes = new Uint8Array(zipBinary.length);
for (var i = 0; i < zipBinary.length; ++i) {
zipBinaryBytes[i] = zipBinary.charCodeAt(i);
}
zipBinary = new Blob([zipBinaryBytes], { type: 'application/zip' });
// rest of code as I suggested above...
(注意:application/zip
是 zip 文件的官方 MIME 类型,而不是 application/x-zip-compressed
)
如果您是 HTTP 协议的专家并且真的想要完全手写 HTTP 请求体,那么您需要发送一个类型化数组而不是字符串,因为 XMLHttpRequest API will encode a regular string as UTF-8 before passing off the data to the server. This can be done using the TextEncoder
API since Chrome 38+,应用到你的代码如下:
// Was: XHR.send(prefix + zipBinary + postfix);
// New
XHR.send(new TextEncoder().encode(prefix + zipBinary + postfix));
注意:您很少需要手动构造请求正文。除非您知道自己在做什么,否则 必须手动构建请求主体通常表明您做错了。
我正在编写一个 Chrome 扩展,需要构建自定义表单数据以将 Zip 文件(我不能使用真正的 HTML 表单)上传到服务器(不是矿)。 我在这里找到了一种方法 - https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Forms/Sending_forms_through_JavaScript(最后一节 - 处理二进制数据)。
它可以很好地处理明文文件,但我想发送二进制的 Zip。
似乎 JavaScript 无法处理二进制和非二进制的连接,并在我的文件中添加了一些 0Xc2 字符)-:
我也在 http://footle.org/2007/07/31/binary-multipart-posts-in-javascript/ 找到了解决方案,
但它使用 Components.classes["@mozilla.org/io/string-input-stream;1"]
,这在 Chrome 扩展中不可用。
如何将二进制 zip 文件与字符串连接起来并将其上传到服务器?
function sendData(zipBinary) {
var XHR = new XMLHttpRequest();
var boundary = "----WebKitFormBoundary3n9vu9ZOkCPW4HAw";
var prefix = "";
var postfix = "";
prefix += "--" + boundary + "\r\n";
prefix += 'content-disposition: form-data; '
+ 'name="' + 'UploadedFile' + '"; '
+ 'filename="' + 'hello.zip' + '"\r\n';
prefix += 'Content-Type: ' + 'application/x-zip-compressed' + '\r\n';
prefix += '\r\n';
postfix += '\r\n';
// Once we are done, we "close" the body's request
postfix += "--" + boundary + "--";
postfix += '\r\n';
XHR.addEventListener('load', function(event) {
alert('Yeah! Data sent and response loaded.');
});
XHR.addEventListener('error', function(event) {
alert('Oups! Something goes wrong.');
});
XHR.open('POST', 'https://example.com');
XHR.setRequestHeader('Content-Type','multipart/form-data; boundary=' + boundary);
XHR.send(prefix + zipBinary + postfix); // <----
}
您是否阅读了所链接文章中的 section about FormData?因为这是通过 XMLHttpRequest API 发送文件的最佳解决方案。这种 API 优于字符串连接的优点是文件可以以流方式上传,而不必在发送前完全缓冲在内存中。
假设zipBinary
是一个Blob
或File
对象,你可以上传一个文件如下:
function sendData(zipBinary) {
var xhr = new XMLHttpRequest();
var fd = new Formdata();
fd.append('hello.zip', zipBinary);
xhr.onload = function() {
// Request completed! Use xhr.status and/or xhr.responseText to
// check the server's response status code and response body.
};
xhr.onerror = function() {
// Aw. Network error.
};
xhr.open('POST', 'https://example.com/');
xhr.send(fd);
}
如果zipBinary
不是Blob or File对象,而是一串二进制数据,那么您可以将其转换为具有指定MIME-type的Blob,如下所示:
function sendData(zipBinary) {
var zipBinaryBytes = new Uint8Array(zipBinary.length);
for (var i = 0; i < zipBinary.length; ++i) {
zipBinaryBytes[i] = zipBinary.charCodeAt(i);
}
zipBinary = new Blob([zipBinaryBytes], { type: 'application/zip' });
// rest of code as I suggested above...
(注意:application/zip
是 zip 文件的官方 MIME 类型,而不是 application/x-zip-compressed
)
如果您是 HTTP 协议的专家并且真的想要完全手写 HTTP 请求体,那么您需要发送一个类型化数组而不是字符串,因为 XMLHttpRequest API will encode a regular string as UTF-8 before passing off the data to the server. This can be done using the TextEncoder
API since Chrome 38+,应用到你的代码如下:
// Was: XHR.send(prefix + zipBinary + postfix);
// New
XHR.send(new TextEncoder().encode(prefix + zipBinary + postfix));
注意:您很少需要手动构造请求正文。除非您知道自己在做什么,否则 必须手动构建请求主体通常表明您做错了。