Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSON.parse returns string instead of object

im writing a websocket client and i would like to receive messages as json strings. For this I need a login. And if the login isn't true i send a json string with nosuccess. JSON String:

{"action":"login","args":["nosuccess"]}

On the client I'm using this to get the string:

WebSocket socket = new WebSocket("ws://localhost:2555/api");

socket.onmessage = function(evt) {
    console.log(evt.data);
    console.log(typeof(evt.data));
    onMessage(evt);
}
function onMessage(evt) {
var data = JSON.parse(evt.data);
var action = data.action;
var args = data.args;
console.log(data);
console.log(typeof(data));
console.log(action);
console.log(args);

But the type of data is a string... But why?

evt.data returns:

 "{\"action\":\"login\",\"args\":[\"nosuccess\"]}"

data returns:

 {"action":"login","args":["nosuccess"]}

The WebSocket server is a jetty Server which sends a string and a string array in json parsed in json with gson.toJson(class) Gson by Google. The Class is a class containing String action and String array args.

Complete source code of websocket.js:

var socket;

function openWebsocket(adress) {
    socket = new WebSocket(adress);
    socket.onopen = function(evt) {
        console.log("Socket opened [" + adress + "]");
    };
    socket.onclose = function(evt) {
        loadPage("login.html");
        console.log("Socket closed [" + evt.code + "]");
    }
    socket.onmessage = function(evt) {
        onMessage(evt);
    }
    socket.onerror = function(evt) {
        console.log("Socket couldn't connect [" + evt.message + "]");
        showMessage("fa-exclamation-circle", "Socket couldn't be established!", 1000);
    }
}

function onMessage(evt) {
    var data = JSON.parse(evt.data);
    var action = data.action;
    var args = data.args;
    console.log(data);
    console.log(typeof(data));
    console.log(action);
    console.log(args);
    $(".card-container h3").html(data);

    if(action == "login") {
        if(args[0] == "success") {
            loadPage("dashboard.htm");
            currentpage = "dashboard.htm";
            showMessage("fa-check", "Du wurdest erfolgreich eingeloggt", 2000);
        } else if(args[0] == "nosuccess") {
            loadPage("login.html");
            currentpage = "login.html";
            showMessage("fa-exclamation-circle", "Falscher Benutzername oder falsches Passwort", 2000);
        } else if(args[0] == "unauthenticated") {
            loadPage("login.html");
            currentpage = "login.html";
            showMessage("fa-exclamation-circle", "Login failure: not authenticated", 2000);
        }
    }

}

function sendMessage(json) {
    $(".card-container h3").html(JSON.stringify(json));
    console.log(JSON.stringify(json));
    socket.send(JSON.stringify(json));
}

If I change this line:

 var data = JSON.parse(evt.data);

to this:

var data = JSON.parse("{\"action\":\"login\",\"args\":[\"nosuccess\"]}");

Then it is a json object, but when I use evt.data then it is a string. If I change the line to this:

    var data = JSON.parse(JSON.parse(evt.data));

Then it works, but why, normally it should do it with only one JSON.parse, should it?

like image 435
Nightloewe Avatar asked Feb 27 '17 20:02

Nightloewe


People also ask

Does JSON parse return an object?

The JSON. parse() method parses a string and returns a JavaScript object. The string has to be written in JSON format.

How do I access a JSON object?

To access the JSON object in JavaScript, parse it with JSON. parse() , and access it via “.” or “[]”.

How do I convert a string to JSON?

String data can be easily converted to JSON using the stringify() function, and also it can be done using eval() , which accepts the JavaScript expression that you will learn about in this guide.

What is the difference between JSON parse and JSON Stringify?

JSON. parse() is used to convert String to Object. JSON. stringify() is used to convert Object to String.


4 Answers

This seems to be fairly consistent with over-stringified strings. For example I loaded a text file using FileReader.readAsText that came with \n and \r which rendered in the console, so I did - (JSON.stringify(reader.result)).replace(/(?:\\[rn])+/g, '') first to see the symbols, then to get rid of them. Taking that and running JSON.parse() on it converts it to a non-escaped string, so running JSON.parse() again creates an object.

If you do not stringify your string, it will convert to an object and often it is not necessary but if you have no control over the obtained value, then running JSON.parse() twice will do the trick.

like image 200
DerpSuperleggera Avatar answered Oct 18 '22 18:10

DerpSuperleggera


As others have stated in the comments it seems that this issue has been solved. If you are receiving a response from the server as a "stringified object" then you can turn it into a normal object with JSON.parse() like so:

var stringResponse = '{"action":"login","args":["nosuccess"]}';

var objResponse = JSON.parse(stringResponse);

console.log(objResponse.args);

You can also try out the above code here.

As for why the server is returning a string when you really wanted an object, that really comes down to your backend code, what library you are using, and the transport protocol. If you just want your front-end code to work, use JSON.parse. If you want to edit how the backend responds, please provide more information.

like image 41
Jim Avatar answered Oct 18 '22 20:10

Jim


@DerpSuperleggera is correct. The issue was indeed an over-stringified string

let arr = "[\"~#iM\",[\"is_logged_out_token\",false,\"token_type\",\"Bearer\"]]"

So to parse it as an object, I just ran it through JSON.parse twice and that did the trick!

let obj = JSON.parse(JSON.parse(arr))
like image 4
Madhur Avatar answered Oct 18 '22 18:10

Madhur


The checked response is correct in that it seems to be an issue of over-stringified strings. I came across it from using AWS Amplify AWSJSON type in my project. The solution that worked for me was to iterate multiple (twice) to get an object.

Wrote a simple JS function that when used to parse will return an object. There isn't really error checking, but a starting point.

    export function jsonParser(blob) {
       let parsed = JSON.parse(blob);
       if (typeof parsed === 'string') parsed = jsonParser(parsed);
       return parsed;
    }

like image 2
Martin Rojas Avatar answered Oct 18 '22 20:10

Martin Rojas