Попытка использовать 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 = "\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 , который снова работает на Mac. Сервер и клиент находятся на одной машине. То же самое происходит с любым файлом, который я пытаюсь загрузить, я просто выбрал PNG, потому что это был наиболее очевидный пример.
<input type="file">
поля)(Ниже приводится поздний, но полный ответ)
Поддержка методов FileReader
FileReader.readAsBinaryString()
является устаревшим. Не используйте это! Его больше нет в рабочем проекте W3C File API :void abort(); void readAsArrayBuffer(Blob blob); void readAsText(Blob blob, optional DOMString encoding); void readAsDataURL(Blob blob);
NB: Обратите внимание, что
File
это своего рода расширеннаяBlob
структура.Mozilla все еще реализует
readAsBinaryString()
и описывает его в документации MDN FileApi :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 () НЕ является стандартом и может не поддерживаться в Chrome.
Решения
Итак, у вас есть несколько вариантов:
send()
FileReader.result
изFileReader.readAsArrayBuffer ( fileObject )
. Этим более сложно манипулировать (для этого вам придется сделать отдельный send ()), но это РЕКОМЕНДУЕМЫЙ ПОДХОД .send()
FileReader.result
изFileReader.readAsDataURL( fileObject )
. Он создает бесполезные накладные расходы и задержку сжатия, требует этапа распаковки на стороне сервера, НО его легко манипулировать как строку в Javascript.sendAsBinary()
FileReader.result
FileReader.readAsBinaryString( fileObject )
MDN заявляет, что:
источник
FileReader.readAsDataURL
иonload
обработчик вместо того , чтобы просто посылающегоevent.target.result
(который не является чистым base64 строки в кодировке) вы сначала очистите его с помощью некоторого регулярного выраженияevent.target.result = event.target.result.match(/,(.*)$/)[1]
и отправьте реальный base64 на сервер для декодирования.event.target.result.split(",", 2)[1]
, а неmatch
.Лучший способ в браузерах, которые его поддерживают, - это отправить файл как 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
. См. Документацию . Конечно, это также потребует изменений на стороне сервера.// 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+).
источник
FormData
. Кажется, все используют форму, а все, что им нужно, это загрузить один файл ... Спасибо!