Websocket sending blob object instead of string

Viewed 6959

I am somehow able to run Websocket but the problem is that it is sending me object blob on on message event while i want to send the text.

Here is my websocket server code:

const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 })

var sockets = [];

wss.on('connection', ws => {
    //var id = ws.upgradeReq.headers['sec-websocket-key'];
    //console.log("New connection id ::", id);
    //w.send(id);
    sockets.push(ws);
    console.log("New client connected"+ ws);

  ws.on('message', message => {

    console.log(`Received message => ${message}`)

    //var id = ws.upgradeReq.headers['sec-websocket-key'];
    //var mes = JSON.parse(message);

    //sockets[message.to].send(mes.message);
     // console.log('Message on :: ', id);
    //console.log('On message :: ', message);
    sockets.forEach(w=> {
        w.send(message);
    });
  })

  ws.send('Welcome by server!')
})

Client side Code Excerpt

connection.onmessage = (e) => {
  document.getElementById("ReceviedText").innerHTML += ("<li>" + e.data + "</li>");

   // ReceviedText
  console.log(e.data);
  console.log(e);

  var reader = new FileReader(e.data);
  console.log(reader.result);

  //console.log(reader.readAsText());
  console.log(reader.readAsText(e.data));

}

I found that I can convert blob to string using file reader but it returning null.

7 Answers

I had the same issue with an object array. Fixed it by converting the data as a JSON string with JSON.stringify. On the client, you can get the data with JSON.parse.

Server

sockets.forEach(w => {
  w.send(JSON.stringify(message));
});

Client

connection.onmessage = (message: object) => {
  console.log(JSON.parse(message['data']));
}

I had the same issue when I send the message via firefox web socket client extension. On the server side, I fixed it by converting the data as a JSON string with JSON.stringify. On the client, you can get the data with JSON.parse.

Server

wss.clients.forEach(function each(client) {
      if (client !== ws && client.readyState === WebSocket.OPEN) {
        console.log('data %s', data);
        // client.send(data);
        // this is to solve the issue where web socket client
        // send data as blob instead of string
        client.send(JSON.stringify(data));
      }
    });

Client

ws.onmessage = (e) => {
      const arr = JSON.parse(e.data).data;
      let newData = '';
      arr.forEach((element) => {
        newData+=String.fromCharCode(element);
      });
      console.log('newData ', newData);
    };

I have resolved this issue..:

//index.js (Server)

const express = require('express');
const http = require('http');
const WebSocket = require("ws");
const PORT = 3000;

const server = http.createServer(express);
const wss = new WebSocket.Server({server});

wss.on('connection',function connection(ws){
    ws.on('message',function incoming(message){
        console.log("Received: "+message);
        
        wss.clients.forEach(function each(client){
            if(client!==ws && client.readyState===WebSocket.OPEN)
            {
                client.send(JSON.stringify(message));
            }
        });
    });
});

server.listen(PORT,()=>console.log(`Server is listening to PORT ${PORT}`));
<!-- index.html page -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Client 1</title>
</head>
<body>
   <input type="text" name="messageBox" id="messageBox">
   <button type="button" id="sendBtn">Send</button>

   <div class="container">
       <div class="receive-message">
           <p id="message"></p>
       </div>
   </div>
</body>
<script type="text/javascript">

    var sendBtn = document.getElementById("sendBtn");
    var messageBox = document.getElementById("messageBox");

    var socket = new WebSocket("ws://localhost:3000");

    sendBtn.addEventListener("click",()=>{
        let val = messageBox.value;
        socket.send(val);
    });

    socket.addEventListener("open",function(event){
        socket.send("Connected.....");
    });

    socket.addEventListener('message',function(event){
        var string_arr =JSON.parse(event['data']).data;
        var string = "";

        string_arr.forEach(element => {
            string+=String.fromCharCode(element);
        });
        
        console.log(string);
    });
</script>
</html>

FileReader.readAsText() is an event based API, as mentioned in MDN docs.

So you need to set reader.onload:

  const reader = new FileReader();
  reader.onload = function(evt) {
    console.log(evt.target.result);
  };
  reader.readAsText(e.data);

Also, Blob.text() can be used.

websocket.addEventListener("message", e => {        
    e.data.text().then(txt=>console.log(txt))   
});

Docs describes the difference between these two:

Blob.text() returns a promise, whereas FileReader.readAsText() is an event based API. Blob.text() always uses UTF-8 as encoding, while FileReader.readAsText() can use a different encoding depending on the blob's type and a specified encoding name.

on the server side

ws.on('message', function message(data, isBinary) {
    wss.clients.forEach(function each(client) {
        if (client !== ws && client.readyState === WebSocket.OPEN) {
            client.send(data, { binary: isBinary });
        }
    });
});

and on the client side

socket.addEventListener('message', (event, isBinary) => 
    console.log(event.data)
})

the isBinary parameter solved the problem for me

I also faced the same issue. I can fix it by adding {binary:isBinary} in Server.

Here is my code:-

wss.on('connection', function connection(ws) {
  ws.on('message', function incoming(data,isBinary) {
    wss.clients.forEach(function each(client) {
      if (client !== ws && client.readyState === WebSocket.OPEN) {
        client.send(data, { binary: isBinary });
      }
    })
  })
})

I had a particularly confusing situation, while using Koa, that required the client side to do double duty:

//server side
myCtx.websocket.send( JSON.stringify( message ) );

// client side
let msg = JSON.parse( event.data );
let data = JSON.parse( String.fromCharCode( ...msg.data ) );

On the server if I just sent the message, it would show up as a blob on the client side.

On the client side, after I parsed the event.data the data was a binary array, [ 123, 34, 116...] so had to do the String.fromCharCode() call. The three dots ... is the javascript spreader operator, to get the whole array.

Related