web-dev-qa-db-ja.com

JSON.parseはオブジェクトではなく文字列を返します

webSocketクライアントを書いているIMとJSON文字列としてメッセージを受信したいと思います。これにはログインが必要です。ログインが正しくない場合、json文字列を送信しますが成功しません。 JSON文字列:

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

クライアントでは、これを使用して文字列を取得しています:

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

しかし、データのタイプは文字列です...しかし、なぜですか?

evt.dataは以下を返します。

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

データが返されます:

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

WebSocketサーバーは、Googleがgson.toJson(class)Gsonでjsonで解析したjsonの文字列と文字列配列を送信する桟橋サーバーです。 Classは、StringアクションとString配列引数を含むクラスです。

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));
}

この行を変更した場合:

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

これに:

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

それはjsonオブジェクトですが、evt.dataを使用すると、文字列になります。行をこれに変更すると:

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

それは動作しますが、なぜ、通常は1つのJSON.parseだけでそれを行う必要がありますか?

21
Nightloewe

これは、over-stringified文字列とかなり一貫しているようです。たとえば、コンソールでレンダリングされた_FileReader.readAsText_および_\n_に付属する_\r_を使用してテキストファイルをロードしたため、最初にシンボルを表示するために_(JSON.stringify(reader.result)).replace(/(?:\\[rn])+/g, '')_を、次にそれらを取り除きます。それを取り、JSON.parse()を実行すると、エスケープされない文字列に変換されるため、JSON.parse()を再度実行するとオブジェクトが作成されます。

文字列を文字列化しない場合、オブジェクトに変換され、多くの場合必要ありませんが、取得した値を制御できない場合は、JSON.parse()を2回実行するとうまくいきます。

15

他の人がコメントで述べているように、この問題は解決されたようです。サーバーから「文字列化オブジェクト」として応答を受信して​​いる場合、JSON.parse()で通常のオブジェクトに変換できます。 :

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

var objResponse = JSON.parse(stringResponse);

console.log(objResponse.args);

上記のコードを試すこともできます here

オブジェクトが本当に必要なときにサーバーが文字列を返す理由については、バックエンドコード、使用しているライブラリ、およびトランスポートプロトコルによって決まります。フロントエンドコードを機能させるだけの場合は、JSON.parseを使用します。バックエンドの応答方法を編集する場合は、詳細を入力してください。

1
Jim