it-swarm.com.de

Wie gehe ich mit komisch kombinierten Websocket-Nachrichten um?

Ich verbinde mich mit einem externen Websocket-API mit der node ws-Bibliothek (Knoten 10.8.0 auf Ubuntu 16.04). Ich habe einen Listener, der den Json einfach parst und an den Callback weiterleitet:

this.ws.on('message', (rawdata) => {
    let data = null;
    try {
        data = JSON.parse(rawdata);
    } catch (e) {
        console.log('Failed parsing the following string as json: ' + rawdata);
        return;
    }
    mycallback(data);
});

Ich erhalte jetzt Fehler, bei denen die rawData wie folgt aussieht (ich habe irrelevante Inhalte formatiert und entfernt):

�~A
{
    "id": 1,
    etc..
}�~�
{
    "id": 2,
    etc..

Ich wunderte mich dann; Was sind diese Charaktere? Als ich die Struktur sah, dachte ich zunächst, dass das erste komische Zeichen eine öffnende Klammer eines Arrays ([) sein muss und das zweite ein Komma (,), damit ein Array von Objekten erstellt wird. 

Dann habe ich das Problem weiter untersucht, indem ich die Variable rawdata in eine Datei geschrieben habe, wenn ein JSON-Parsing-Fehler auftritt. In ungefähr einer Stunde wurden ungefähr 1500 dieser Fehlerdateien gespeichert, was bedeutet, dass dies viel ist. Ich catte ein paar dieser Dateien im Terminal, von denen ich ein Beispiel hochgeladen habe:

 enter image description here

Einige Dinge sind hier interessant:

  1. Die Dateien beginnen immer mit einem dieser seltsamen Zeichen. 
  2. Die Dateien scheinen aus mehreren Nachrichten zu bestehen, die separat empfangen werden sollten. Die seltsamen Zeichen trennen diese einzelnen Nachrichten.
  3. Die Dateien enden immer mit einem unfertigen Json-Objekt.
  4. Die Dateien sind unterschiedlich lang. Sie haben nicht immer die gleiche Größe und werden daher nicht auf eine bestimmte Länge abgeschnitten.

Ich bin nicht sehr erfahren mit Websockets, aber könnte es sein, dass mein Websocket irgendwie einen Nachrichtenstrom empfängt, der mit diesen seltsamen Zeichen als Trennzeichen zusammengefügt wird, und dann die letzte Nachricht zufällig abschneidet? Vielleicht, weil ich ständig einen sehr schnellen Nachrichtenstrom bekomme? 

Oder könnte es an einer Fehlerseite (oder Funktionalität) des Servers liegen, indem diese einzelnen Nachrichten kombiniert werden? 

Weiß jemand, was hier los ist? Alle Tipps sind willkommen!

[BEARBEITEN]

@bendataclear schlug vor, es als utf8 zu interpretieren. Also habe ich es getan und ich habe einen Screenshot der Ergebnisse unten eingefügt. Der erste Druck ist wie er ist und der zweite als utf8 interpretiert. Für mich sieht das nicht nach etwas aus. Ich könnte natürlich in utf8 konvertieren und dann nach diesen Zeichen spalten. Obwohl die letzte Nachricht immer abgeschnitten ist, werden dadurch zumindest einige Nachrichten lesbar. Andere Ideen sind jedoch immer noch willkommen.

 enter image description here

23
kramer65

Ich gehe davon aus, dass Sie nur mit englischen/ASCII-Zeichen arbeiten und wahrscheinlich etwas den Stream durcheinander gebracht hat. ( [~ # ~] note [~ # ~]: Ich nehme an) , es gibt keine Sonderzeichen Wenn dem so ist, schlage ich vor, dass Sie den gesamten json-String in diese Funktion übergeben:

_function cleanString(input) {
    var output = "";
    for (var i=0; i<input.length; i++) {
        if (input.charCodeAt(i) <= 127) {
            output += input.charAt(i);
        }
    }
    console.log(output);
}

//example
cleanString("�~�")_

Sie können auf verweisen. So entfernen Sie ungültige UTF-8-Zeichen aus einer JavaScript-Zeichenfolge

[~ # ~] edit [~ # ~]

Aus einem Artikel der Internet Engineering Task Force (IETF) ,

Eine häufige Klasse von Sicherheitsproblemen tritt auf, wenn Textdaten mit der falschen Codierung gesendet werden. Dieses Protokoll gibt an, dass Nachrichten mit einem Textdatentyp (im Gegensatz zu binären oder anderen Typen) UTF-8-codierte Daten enthalten. Obwohl die Länge immer noch angegeben ist und Anwendungen, die dieses Protokoll implementieren, die Länge verwenden sollten, um zu bestimmen, wo der Frame tatsächlich endet, und um Daten in einem falschen Zustand zu senden


Die "Nutzdaten" sind Textdaten, die als UTF-8 codiert sind. Beachten Sie, dass ein bestimmter Textrahmen möglicherweise eine teilweise UTF-8-Sequenz enthält. Die gesamte Nachricht MUSS jedoch gültiges UTF-8 enthalten. Ungültiges UTF-8 in neu zusammengesetzten Nachrichten wird wie in Fehlerbehandlung in UTF-8-codierten Daten beschrieben behandelt, in der Wenn ein Endpunkt angegeben ist ist, einen Bytestream als UTF-8 zu interpretieren, stellt jedoch fest, dass der Bytestream kein gültiger UTF-8-Stream ist, und der Endpunkt MUSS die WebSocket-Verbindung fehlschlagen lassen. Diese Regel gilt sowohl beim Eröffnungs-Handshake als auch beim anschließenden Datenaustausch.

Ich bin der festen Überzeugung, dass Ihr Fehler (oder Ihre Funktionalität) von der Serverseite ausgeht, die Ihre einzelnen Nachrichten kombiniert. Daher schlage ich vor, eine Logik zu entwickeln, mit der sichergestellt wird, dass alle Ihre Zeichen [~ # ~ ] muss [~ # ~] von Unicode zu ASCII) konvertiert werden, indem die Zeichen zuerst als UTF-8 codiert werden. Möglicherweise möchten Sie auch _npm install --save-optional utf-8-validate_, um effizient zu überprüfen, ob eine Nachricht gültiges UTF-8 enthält, wie in der Spezifikation gefordert.

Möglicherweise möchten Sie auch eine if -Bedingung übergeben, um einige Überprüfungen durchzuführen.

_this.ws.on('message', (rawdata) => {
    if (message.type === 'utf8') { // accept only text
    }
_

Ich hoffe das hilft weiter.

4
antzshrek

Das Problem, das Sie haben, ist, dass die eine Seite eine JSON in einer anderen Codierung sendet, als die andere Seite sie interpretiert.

Versuchen Sie, dieses Problem mit folgendem Code zu lösen:

const { StringDecoder } = require('string_decoder');

this.ws.on('message', (rawdata) => {
    const decoder = new StringDecoder('utf8');
    const buffer = new Buffer(rawdata);
    console.log(decoder.write(buffer));
});

Oder mit utf16:

const { StringDecoder } = require('string_decoder');

this.ws.on('message', (rawdata) => {
    const decoder = new StringDecoder('utf16');
    const buffer = new Buffer(rawdata);
    console.log(decoder.write(buffer));
});

Bitte lesen Sie: String Decoder Dokumentation

0
Bharata

Es scheint, Ihre Ausgabe enthält einige Leerzeichen. Wenn Sie Leerzeichen haben oder wenn Sie Sonderzeichen finden, verwenden Sie Unicode, um sie vollständig auszufüllen.

Hier ist die Liste der Unicode-Zeichen

Das könnte helfen, denke ich.

0
Pravi

Diese Zeichen werden als "REPLACEMENT CHARACTER" (Ersetzungszeichen) bezeichnet. Sie ersetzen ein unbekanntes, nicht erkanntes oder nicht darstellbares Zeichen.

Von: https://en.wikipedia.org/wiki/Specials_(Unicode_block)

Das Ersetzungszeichen (oft ein schwarzer Diamant mit weißem Fragezeichen oder ein leeres Quadrat) ist ein Symbol, das im Unicode-Standard am Codepunkt U + FFFD in der Tabelle Specials zu finden ist. Es wird verwendet, um Probleme anzuzeigen, wenn ein System einen Datenstrom nicht mit einem korrekten Symbol darstellen kann. Es wird normalerweise angezeigt, wenn die Daten ungültig sind und keinem Zeichen entsprechen

Überprüfen des Abschnitts 8 des WebSocket-Protokolls Fehlerbehandlung :

8,1. Fehler in UTF-8 vom Server behandeln

Wenn ein Client einen Bytestrom als UTF-8 interpretieren soll, er jedoch feststellt, dass der Bytestrom kein gültiger UTF-8-Stream ist, MÜSSEN alle Bytes oder Folgen von Bytes, die keine gültigen UTF-8-Sequenzen sind, als interpretiert werden U + FFFD ERSATZZEICHEN.

8,2. Fehler in UTF-8 vom Client behandeln

Wenn ein Server einen Byte-Datenstrom als UTF-8 interpretieren soll, der Byte-Datenstrom jedoch kein gültiger UTF-8-Datenstrom ist, ist das Verhalten undefiniert. Ein Server könnte die Verbindung schließen, ungültige Bytefolgen in U + FFFD-ERSATZZEICHEN konvertieren, die Daten wortgetreu speichern oder eine anwendungsspezifische Verarbeitung durchführen. Im WebSocket-Protokoll geschichtete Unterprotokolle definieren möglicherweise ein bestimmtes Verhalten für Server.


Hängt von der Implementierung oder der verwendeten Bibliothek ab, wie Sie damit umgehen, zum Beispiel aus diesem Beitrag Implementieren von Web Socket-Servern mit Node.js :

socket.ondata = function(d, start, end) {
    //var data = d.toString('utf8', start, end);
    var original_data = d.toString('utf8', start, end);
    var data = original_data.split('\ufffd')[0].slice(1);
    if (data == "kill") {
        socket.end();
    } else {
        sys.puts(data);
        socket.write("\u0000", "binary");
        socket.write(data, "utf8");
        socket.write("\uffff", "binary");
    }
};

Wenn in diesem Fall ein gefunden wird, wird Folgendes ausgeführt:

var data = original_data.split('\ufffd')[0].slice(1);
if (data == "kill") {
    socket.end();
} 

Eine weitere Sache, die Sie tun können, ist, den Knoten auf den neuesten Stand zu bringen. Von diesem Beitrag OpenSSL und Breaking UTF-8 Change (behoben in Node v0.8.27 und v0.10.29) :

Wenn Sie versuchen, eine Zeichenfolge mit einem nicht übereinstimmenden Ersatzpaar zu übergeben, ersetzt Node dieses Zeichen durch das unbekannte Unicode-Zeichen (U + FFFD). Um das alte Verhalten zu erhalten, setzen Sie die Umgebungsvariable NODE_INVALID_UTF8 auf nichts (auch nichts). Wenn die Umgebungsvariable überhaupt vorhanden ist, wird sie auf das alte Verhalten zurückgesetzt.

0
nbari