Как отправить двоичные данные в чистом JavaScript?

Я хочу отправить бинарные данные с html-страницы на свой сервер через JavaScript, но сервер получил не те байты. Полученные байты, похоже, преобразуются в строку юникода, см. следующий пример:

xhr.open('POST', '/check', true);
xhr.setRequestHeader('cache-control', 'no-cache');
xhr.setRequestHeader('Content-Type', 'application/octet-stream');
xhr.send('\x41\xFE\x80');

Сервер должен получить «Aþ€», но он получит A├¥┬Ç.

Я тестировал много вещей, таких как:

//xhr.overrideMimeType('text/plain; charset=iso-8859-1');
//xhr.setRequestHeader('Content-type', 'text/plain; charset=iso-8859-1');
//xhr.setRequestHeader('Content-type', 'application/xml; charset=UTF-8');
//xhr.overrideMimeType('text/plain; charset=x-user-defined');
//xhr.overrideMimeType('text/plain; charset=x-user-defined');

На стороне сервера я запускаю нагромождение (http://локальный:5000/index.html), а $env->{'CONTENT_LENGTH'} равно 5, поэтому кажется, что сервер действительно получает 5 байтов A├¥┬Ç.

Любой намек на то, как получить исходные двоичные данные, был бы замечательным.

Да, я знаю этот образец и использовал его. ИМХО, мой Javascript правильный, возможно, скрипт на сервере вызывает эту ошибку...

Codr 25.02.2019 12:58
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
4
2
2 015
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

IMHO my Javascript is correct

Нет. Как я намекнул в комментарии, используйте Uint8Array, а не строки, для двоичных данных:

xhr.send(new Uint8Array([0x41, 0xFE, 0x80]));

Если у вас уже есть строка... это должно работать:

xhr.send(new Uint8Array(Array.from('\x41\xFE\x80').map(x => x.charCodeAt(0)))

Объяснение: Спецификация для send говорит:

If body is a Document, then set request body to body, serialized, converted to Unicode, and UTF-8 encoded.

Otherwise, set request body and extractedContentType to the result of extracting body.

String не является Document, поэтому первый вариант не применяется. Определение «извлечение» находится в fetch спецификация:

USVString:

Set action to an action that runs UTF-8 encode on object.

Set Content-Type to text/plain;charset=UTF-8.

Set source to object.

И вы можете увидеть, как выглядит кодировка UTF-8 вашей строки:

new TextEncoder().encode('\x41\xFE\x80')
// => Uint8Array(5) [65, 195, 190, 194, 128]

Оно работает! Спасибо! Но почему решение от Adelin не работает?

Codr 25.02.2019 13:40

Я это прокомментировал. Blob — это просто абстракция над произвольным контентом, поэтому он не делал ничего существенно отличного от вас: в конце концов, это все еще была переданная строка. Не используйте строки для двоичных данных.

Amadan 25.02.2019 13:42

Но я нашел на sendAsBinary: метод send() теперь поддерживает двоичные данные и теперь должен использоваться вместо этого. Значит, Отправить() тоже должен работать!?

Codr 26.02.2019 10:04

@Codr: Из вашей ссылки: «Предупреждение: этот метод устарел и не должен использоваться. Вместо этого вы должны просто использовать метод send(), который теперь поддерживает двоичные данные в различных формах». И send() действительно работает — я только что продемонстрировал это в своем ответе.

Amadan 26.02.2019 10:06
Uint8Array (который я использовал) — это своего рода ArrayBufferView. И опять же, Blob — это просто контейнер, и он будет вести себя так же, как и любой источник данных, которым вы его инициализируете: если вы инициализируете его 5-байтовой строкой, он отправит 5 байтов точно так же, как и строка. Проверьте это: var blob = new Blob(['\x41\xFE\x80'], {type: 'application/octet-stream'}); var reader = new FileReader(); reader.addEventListener("loadend", () => console.info(reader.result)); reader.readAsArrayBuffer(blob).
Amadan 26.02.2019 10:17

Другие вопросы по теме