尝试使用fileReader.readAsBinaryString通过AJAX将PNG文件上传到服务器,剥离代码(fileObject是包含我文件信息的对象);
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 = "\r\n";
//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编码函数
function utf8encode(string) {
string = string.replace(/\r\n/g,"\n");
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;
)
然后在原始代码中
//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。我一直在Firefox和Chrome上对它进行测试,两者都在Mac上获得相同的结果。后端上传由NGINX Upload Module处理,再次在Mac上运行。服务器和客户端位于同一台计算机上。我尝试上传的任何文件都会发生同样的事情,我只选择了PNG,因为这是最明显的例子。
答案 0 :(得分:98)
(以下是一个迟到但完整的答案)
FileReader.readAsBinaryString()
已弃用。不要使用它!它已不在W3C File API working draft:
void abort();
void readAsArrayBuffer(Blob blob);
void readAsText(Blob blob, optional DOMString encoding);
void readAsDataURL(Blob blob);
注意:请注意File
是一种扩展的Blob
结构。
Mozilla仍在实施readAsBinaryString()
并在MDN FileApi documentation中对其进行了描述:
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);
readAsBinaryString()
弃用背后的原因在于我认为如下:JavaScript字符串的标准是DOMString
,它只接受UTF-8字符,而不是随机二进制数据。所以不要使用readAsBinaryString(),这根本不安全且符合ECMAScript。
我们知道 JavaScript字符串不应存储二进制数据,但某种类型的Mozilla可以。在我看来这很危险。 Blob
和typed arrays
(ArrayBuffer
以及尚未实施但不必要的StringView
)是出于一个目的而发明的:允许使用纯二进制数据,而不使用UTF- 8个字符串限制。
XMLHttpRequest.send()
具有以下调用选项:
void send();
void send(ArrayBuffer data);
void send(Blob data);
void send(Document data);
void send(DOMString? data);
void send(FormData data);
XMLHttpRequest.sendAsBinary()
具有以下调用选项:
void sendAsBinary( in DOMString body );
sendAsBinary()不是标准,Chrome可能不支持。
所以你有几个选择:
send()
FileReader.result
FileReader.readAsArrayBuffer ( fileObject )
。操作起来比较复杂(你必须为它做一个单独的send()),但它是推荐的方法。send()
FileReader.result
FileReader.readAsDataURL( fileObject )
。它会产生无用的开销和压缩延迟,需要在服务器端进行解压缩步骤但是它很容易在Javascript中作为字符串进行操作。sendAsBinary()
FileReader.result
FileReader.readAsBinaryString( fileObject )
MDN声明:
发送二进制内容的最佳方式(如在文件上传中)正在使用 ArrayBuffers或Blob与send()方法结合使用。然而, 如果要发送可串行的原始数据,请使用sendAsBinary() 相反,或者StringView(非本机)类型的数组超类。
答案 1 :(得分:69)
使用fileReader.readAsDataURL( fileObject )
,这会将其编码为base64,您可以安全地将其上传到服务器。
答案 2 :(得分:18)
支持它的浏览器的最佳方式是将文件作为Blob发送,或者如果需要多部分表单则使用FormData。你不需要FileReader。这比尝试读取数据更简单,更有效。
如果您特别想将其作为multipart/form-data
发送,则可以使用FormData对象:
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);
您也可以直接发送数据,而不是使用multipart/form-data
。请参阅documentation。当然,这也需要服务器端的改变。
// 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 +)。