fileReader.readAsBinaryString to upload files
尝试使用fileReader.readAsBinaryString通过AJAX将PNG文件上传到服务器,并精简代码(fileObject是包含我的文件信息的对象);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | var fileReader = new FileReader(); fileReader.onload = function(e) { var xmlHttpRequest = new XMLHttpRequest(); //Some AJAX-y stuff - callbacks, handlers etc. xmlHttpRequest.open("POST", '/pushfile', true); var dashes = '--'; var boundary = 'aperturephotoupload'; var crlf ="\ \ "; //Post with the correct MIME type (If the OS can identify one) if ( fileObject.type == '' ){ filetype = 'application/octet-stream'; } else { filetype = fileObject.type; } //Build a HTTP request to post the file var data = dashes + boundary + crlf +"Content-Disposition: form-data;" +"name="file";" +"filename="" + unescape(encodeURIComponent(fileObject.name)) +""" + crlf +"Content-Type:" + filetype + crlf + crlf + e.target.result + crlf + dashes + boundary + dashes; xmlHttpRequest.setRequestHeader("Content-Type","multipart/form-data;boundary=" + boundary); //Send the binary data xmlHttpRequest.send(data); } fileReader.readAsBinaryString(fileObject); |
在上传之前检查文件的前几行(使用VI)使我
上传后的同一文件显示
所以它看起来像是格式/编码问题,我尝试对原始二进制数据使用简单的UTF8编码功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | function utf8encode(string) { string = string.replace(/\ \ /g,"\ "); var utftext =""; for (var n = 0; n < string.length; n++) { var c = string.charCodeAt(n); if (c < 128) { utftext += String.fromCharCode(c); } else if((c > 127) && (c < 2048)) { utftext += String.fromCharCode((c >> 6) | 192); utftext += String.fromCharCode((c & 63) | 128); } else { utftext += String.fromCharCode((c >> 12) | 224); utftext += String.fromCharCode(((c >> 6) & 63) | 128); utftext += String.fromCharCode((c & 63) | 128); } } return utftext; ) |
然后使用原始代码
1 2 | //Build a HTTP request to post the file var data = dashes + boundary + crlf +"Content-Disposition: form-data;" +"name="file";" +"filename="" + unescape(encodeURIComponent(file.file.name)) +""" + crlf +"Content-Type:" + filetype + crlf + crlf + utf8encode(e.target.result) + crlf + dashes + boundary + dashes; |
这给了我
的输出
仍然不是原始文件=(
如何对文件进行编码/加载/处理以避免编码问题,因此HTTP请求中接收到的文件与上传之前的文件相同。
其他一些可能有用的信息,如果我不是使用fileReader.readAsBinaryString()而是使用fileObject.getAsBinary()来获取二进制数据,则它可以正常工作。但是getAsBinary仅在Firefox中有效。我已经在Mac的Firefox和Chrome中对此进行了测试,两者都得到了相同的结果。后端上传由NGINX上传模块处理,该模块再次在Mac上运行。服务器和客户端在同一台计算机上。我尝试上传的任何文件都发生了同样的事情,我只是选择了PNG,因为这是最明显的例子。
(以下是较晚但完整的答案)
FileReader方法支持
1 2 3 4 | void abort(); void readAsArrayBuffer(Blob blob); void readAsText(Blob blob, optional DOMString encoding); void readAsDataURL(Blob blob); |
NB:请注意,
Mozilla仍实现
1 2 3 4 5 | void abort(); void readAsArrayBuffer(in Blob blob); Requires Gecko 7.0 void readAsBinaryString(in Blob blob); void readAsDataURL(in Blob file); void readAsText(in Blob blob, [optional] in DOMString encoding); |
在我看来,
我们知道JavaScript字符串不应该存储二进制数据,但是Mozilla可以存储二进制数据。我认为这很危险。出于以下目的发明了
XMLHttpRequest上传支持
1 2 3 4 5 6 | void send(); void send(ArrayBuffer data); void send(Blob data); void send(Document data); void send(DOMString? data); void send(FormData data); |
1 | void sendAsBinary( in DOMString body ); |
sendAsBinary()不是标准的,Chrome可能不支持。
解决方案
因此您有几种选择:
MDN指出:
The best way to send binary content (like in files upload) is using
ArrayBuffers or Blobs in conjuncton with the send() method. However,
if you want to send a stringifiable raw data, use the sendAsBinary()
method instead, or the StringView (Non native) typed arrays superclass.
使用
在支持该功能的浏览器中,最好的方法是将文件作为Blob发送,或者如果需要多部分表单,则使用FormData。您不需要为此的FileReader。与尝试读取数据相比,这既简单又有效。
如果您特别想将其作为
1 2 3 4 5 6 7 | var xmlHttpRequest = new XMLHttpRequest(); xmlHttpRequest.open("POST", '/pushfile', true); var formData = new FormData(); // This should automatically set the file name and type. formData.append("file", file); // Sending FormData automatically sets the Content-Type header to multipart/form-data xmlHttpRequest.send(formData); |
您也可以直接发送数据,而不使用
1 2 3 4 5 6 7 8 9 | // file is an instance of File, e.g. from a file input. var xmlHttpRequest = new XMLHttpRequest(); xmlHttpRequest.open("POST", '/pushfile', true); xmlHttpRequest.setRequestHeader("Content-Type", file.type); // Send the binary data. // Since a File is a Blob, we can send it directly. xmlHttpRequest.send(file); |
有关浏览器的支持,请参见:http://caniuse.com/#feat=xhr2(大多数浏览器,包括IE 10)。