Я хочу отправить бинарные данные с 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 правильный, возможно, скрипт на сервере вызывает эту ошибку...



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


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
bodyis aDocument, then set request body tobody, serialized, converted to Unicode, and UTF-8 encoded.Otherwise, set request body and
extractedContentTypeto the result of extractingbody.
String не является Document, поэтому первый вариант не применяется. Определение «извлечение» находится в fetch спецификация:
USVString:
Set
actionto an action that runs UTF-8 encode onobject.Set
Content-Typetotext/plain;charset=UTF-8.Set
sourcetoobject.
И вы можете увидеть, как выглядит кодировка UTF-8 вашей строки:
new TextEncoder().encode('\x41\xFE\x80')
// => Uint8Array(5) [65, 195, 190, 194, 128]
Оно работает! Спасибо! Но почему решение от Adelin не работает?
Я это прокомментировал. Blob — это просто абстракция над произвольным контентом, поэтому он не делал ничего существенно отличного от вас: в конце концов, это все еще была переданная строка. Не используйте строки для двоичных данных.
Но я нашел на sendAsBinary: метод send() теперь поддерживает двоичные данные и теперь должен использоваться вместо этого. Значит, Отправить() тоже должен работать!?
@Codr: Из вашей ссылки: «Предупреждение: этот метод устарел и не должен использоваться. Вместо этого вы должны просто использовать метод send(), который теперь поддерживает двоичные данные в различных формах». И send() действительно работает — я только что продемонстрировал это в своем ответе.
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).