fileReader.readAsBinaryString для загрузки файлов



попытка использовать fileReader.readAsBinaryString для загрузки PNG-файла на сервер через AJAX, урезанный код (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 = "rn";

//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) дает мне



enter image description here



один и тот же файл после загрузки показывает



enter image description here



Так что это похоже на проблему форматирования / кодирования где-то, я попытался использовать простую функцию кодирования UTF8 необработанные двоичные данные



    function utf8encode(string) {
string = string.replace(/rn/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;


что дает мне вывод



enter image description here



все еще не то, что raw-файл был =(



как я могу кодировать/загружать / обрабатывать файл, чтобы избежать проблем с кодировкой, поэтому файл, полученный в HTTP-запросе, совпадает с файлом до его загрузки.



некоторые другие, возможно, полезная информация, если вместо использования fileReader.readAsBinaryString () I используйте fileObject.getAsBinary (), чтобы получить двоичные данные, он отлично работает. Но getAsBinary работает только в Firefox. Я тестировал это в Firefox и Chrome, как на Mac, получая тот же результат в обоих. Серверные загрузки обрабатываются модуль загрузки NGINX, снова работает на Mac. Сервер и клиент находятся на одной машине. То же самое происходит с любым файлом, который я пытаюсь загрузить, я просто выбрал PNG, потому что это был самый очевидный пример.

818   3  

3 ответов:

использовать fileReader.readAsDataURL( fileObject ), Это будет кодировать его в base64, который вы можете безопасно загрузить на свой сервер.

(Ниже приводится поздний, но полный ответ)

поддержка методов FileReader


FileReader.readAsBinaryString() и не рекомендуется. Не используй его! его больше нет в W3C File API working draft:

void abort();
void readAsArrayBuffer(Blob blob);
void readAsText(Blob blob, optional DOMString encoding);
void readAsDataURL(Blob blob);

NB: обратите внимание, что 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


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() не является стандартным и может не поддерживаться в Хром.

решений


Итак, у вас есть несколько вариантов:

  1. send() the FileReader.result на FileReader.readAsArrayBuffer ( fileObject ). Это сложнее манипулировать (вам придется сделать отдельный send () для него), но это РЕКОМЕНДУЕМЫЙ ПОДХОД.
  2. send() the FileReader.result на FileReader.readAsDataURL( fileObject ). Он генерирует бесполезные накладные расходы и задержку сжатия, требует шага декомпрессии на стороне сервера, но его легко манипулировать как строка в Javascript.
  3. быть нестандартным и sendAsBinary() the FileReader.result на FileReader.readAsBinaryString( fileObject )

MDN гласит:

лучший способ отправить двоичный контент (например, при загрузке файлов) - это использовать ArrayBuffers или Blobs в конъюнкции с методом send (). Однако, если вы хотите отправить строковые необработанные данные, используйте sendAsBinary() метод вместо этого, или StringView (не родной) типизированные массивы суперкласса.

лучший способ в браузерах, которые поддерживают его, чтобы отправить файл в виде большого двоичного объекта, или с помощью 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. Смотрите документация. Конечно, для этого понадобится серверные изменения.

// 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+).

Comments

    Ничего не найдено.