I'm trying to send a MessagePack-encoded message from Cowboy to a browser over WebSocket, and received data is always empty or invalid. I'm able to send binary data from JS to my cowboy handler, but not vice versa.
I'm using Cowboy 1.0.4 with official msgpack-erlang
application. I also use msgpack-lite
for my in-browser javascript.
Examples:
websocket_handler
:
websocket_handle({text, <<"return encoded">>}, Req, State) ->
%% sends encoded message to client. Client is unable to decode and fails
{reply, {binary, msgpack:pack(<<"message">>)}, Req, State};
websocket_handle({binary, Encoded}, Req, State) ->
%% Works as expected
lager:info("Received encoded message: ~p", [msgpack:unpack(Encoded)]),
{ok, Req, State};
JS:
var host = "ws://" + window.location.host + "/websocket";
window.socket = new WebSocket(host);
socket.binaryType = 'arraybuffer';
socket.onmessage = function(event) {
var message = msgpack.decode(event.data);
console.log(message);
};
Browser returns an error inside msgpack.min.js:
Error: Invalid type: undefined
...ion n(t){var r=i(t),e=f[r];if(!e)throw new Error("Invalid type: "+(r?"0x"+r.toSt...
If I try to output raw event.data to console, here's what I'm getting:
ArrayBuffer {}
It seems to be empty for some reason. I'm new both to erlang
and msgpack
, and don't know what is going wrong. Thanks for your help!
WebSockets support sending binary messages, too. To send binary data, one can use either Blob or ArrayBuffer object. Instead of calling the send method with string, you can simply pass an ArrayBuffer or a Blob .
WebSocket enables bidirectional, message-oriented streaming of text and binary data between client and server.
The WebSocket protocol allows to send arbitrary binary data (not even UTF-8 or Base-64 encoded) BUT that data are encapsulated in frames whose format is defined by WebSocket protocol (see RFC6455) and has nothing to do with SSH protocol.
Found the reason of my problem. The way how I tried to decode message on the client was wrong:
socket.onmessage = function(event) {
var message = msgpack.decode(event.data);
console.log(message);
};
The right way:
socket.onmessage = function(event) {
var raw_binary_data = new Uint8Array(event.data);
var message = msgpack.decode(raw_binary_data);
console.log(message);
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With