4

I want to send binary data from a html page to my server via JavaScript, but the server received not the same bytes. The received bytes seems to be converted to a unicode string, see the following example:

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

The server should receive 'Aþ€' but it get A├¥┬Ç.

I tested a lot of things like:

//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');

On server side I run plackup (http://localhost:5000/index.html), and $env->{'CONTENT_LENGTH'} is 5, so the server really seems to get the 5 bytes A݀.

Any hint how to receive the original binary data would be great.

2

1 Answer 1

2

IMHO my Javascript is correct

It is not. As I hinted in a comment, use Uint8Array, not strings, for binary data:

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

If you already have a string... this should work:

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

The explanation: The spec for send says:

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 is not a Document, therefore the first option does not apply. The definition of "extracting" is found in the fetch spec:

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.

And you can see how UTF-8 encoding of your string looks like:

new TextEncoder().encode('\x41\xFE\x80')
// => Uint8Array(5) [65, 195, 190, 194, 128]
Sign up to request clarification or add additional context in comments.

5 Comments

It works! Thank you! But why does the solution from Adelin doesn't work?
I commented on it. Blob is just an abstraction over arbitrary content, thus he was not doing anything substantially different than you: in the end, it was still a string that was transmitted. Don't use strings for binary data.
But I found on sendAsBinary: The send() method now supports binary data and should now be used instead. So send() should also work!?
@Codr: From your link: "Warning: This method is obsolete and should not be used. You should instead simply use the send() method, which now supports binary data in various forms." And send() does work - I just demonstrated it in my answer.
Uint8Array (that I used) is a kind of ArrayBufferView. And again, Blob is just a container, and will behave like whatever datasource you initialise it with: if you initialise it with a 5-byte string, it will send 5 bytes just like the string. Check this: var blob = new Blob(['\x41\xFE\x80'], {type: 'application/octet-stream'}); var reader = new FileReader(); reader.addEventListener("loadend", () => console.log(reader.result)); reader.readAsArrayBuffer(blob).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.