web-dev-qa-db-fra.com

Comment gérer des messages websocket étrangement combinés?

Je me connecte à une API websocket externe à l'aide du nœud node ws library (nœud 10.8.0 sur Ubuntu 16.04). J'ai un auditeur qui analyse simplement le JSON et le passe au rappel:

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

Je reçois maintenant des erreurs dans lesquelles la rawData ressemble à ceci (j'ai mis en forme et supprimé le contenu non pertinent):

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

Je me suis alors demandé; quels sont ces personnages? En voyant la structure, j'ai d'abord pensé que le premier signe étrange devait être un crochet ouvrant d'un tableau ([) et le second une virgule (,) afin de créer un tableau d'objets. 

J'ai ensuite étudié le problème plus avant en écrivant la rawdata dans un fichier chaque fois qu'il rencontre une erreur d'analyse JSON. En une heure environ, il a sauvé environ 1500 de ces fichiers d'erreur, ce qui signifie que cela se produit beaucoup. J'ai cated deux de ces fichiers dans le terminal, dont j'ai téléchargé un exemple ci-dessous:

 enter image description here

Quelques choses sont intéressantes ici:

  1. Les fichiers commencent toujours par l'un de ces signes étranges. 
  2. Les fichiers semblent exister à partir de plusieurs messages qui auraient dû être reçus séparément. Les signes étranges séparent ces messages individuels.
  3. Les fichiers se terminent toujours par un objet json inachevé.
  4. Les fichiers sont de longueurs variables. Ils ne sont pas toujours de la même taille et ne sont donc pas coupés sur une longueur spécifique.

Je ne connais pas très bien les Websockets, mais est-il possible que mon Websocket reçoive un flux de messages qu’il concatène ensemble, avec ces signes étranges comme séparateurs, puis coupe le dernier message de manière aléatoire? Peut-être parce que je reçois un flux de messages constant et très rapide? 

Ou pourrait-il être dû à une erreur (ou fonctionnalité) côté serveur dans la mesure où il combine ces messages individuels? 

Est-ce que quelqu'un sait ce qui se passe ici? Tous les conseils sont les bienvenus!

[MODIFIER]

@bendataclear a suggéré de l'interpréter en tant que utf8. Donc je l'ai fait et j'ai collé une capture d'écran des résultats ci-dessous. La première impression est telle quelle et la seconde interprétée comme étant utf8. Pour moi, cela ne ressemble à rien. Je pourrais bien sûr convertir en utf8, puis divisé par ces caractères. Bien que le dernier message soit toujours coupé, cela rendrait au moins certains des messages lisibles. D'autres idées sont toujours les bienvenues.

 enter image description here

23
kramer65

Le problème que vous avez est qu’un côté envoie un JSON dans un encodage différent de l’autre côté qu’il interprète.

Essayez de résoudre ce problème avec le code suivant:

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

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

Veuillez lire: Documentation sur le décodeur de chaînes

0
Bharata

Il semble que votre sortie comporte des espaces. Si vous avez des espaces ou si vous trouvez des caractères spéciaux, utilisez Unicode pour les remplir complètement.

Voici la liste des caractères Unicode

Cela pourrait aider je pense.

0
Pravi

Ces caractères sont appelés "CARACTERE DE REMPLACEMENT" - utilisés pour remplacer un caractère inconnu, non reconnu ou non représentable.

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

Le caractère de remplacement (souvent un diamant noir avec un point d'interrogation blanc ou une case carrée vide) est un symbole de la norme Unicode au point de code U + FFFD du tableau Specials. Il est utilisé pour indiquer des problèmes lorsqu'un système est incapable de restituer un flux de données sous un symbole correct. Il est généralement visible lorsque les données sont invalides et ne correspondent à aucun caractère.

Vérification de la section de la section 8 du traitement des erreurs du protocole WebSocket :

8.1. Gestion des erreurs dans UTF-8 à partir du serveur

Lorsqu'un client doit interpréter un flux d'octets comme UTF-8 mais constate que le flux d'octets n'est pas en fait un flux UTF-8 valide, tous les octets ou séquences d'octets qui ne sont pas des séquences UTF-8 valides DOIVENT être interprétés comme CARACTERE DE REMPLACEMENT U + FFFD.

8.2. Traitement des erreurs dans UTF-8 à partir du client

Lorsqu'un serveur doit interpréter un flux d'octets comme UTF-8 mais constate que le flux d'octets n'est pas en fait un flux UTF-8 valide, le comportement est indéfini. Un serveur peut fermer la connexion, convertir des séquences d'octets non valides en caractères de remplacement U + FFFD, stocker les données intégralement ou effectuer un traitement spécifique à l'application. Les sous-protocoles associés au protocole WebSocket peuvent définir un comportement spécifique pour les serveurs.


Cela dépend de l’implémentation ou de la bibliothèque utilisée, par exemple, à partir de cet article Implémentation de serveurs Web Socket avec 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");
    }
};

Dans ce cas, si un est trouvé, il fera:

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

Vous pouvez également mettre à jour le noeud vers la dernière version stable, à partir de cet article OpenSSL et Breaking UTF-8 Change (corrigé dans les noeuds v0.8.27 et v0.10.29) :

À partir de ces versions, si vous essayez de transmettre une chaîne avec une paire de substitution non appariée, Node remplacera ce caractère par le caractère unicode inconnu (U + FFFD). Pour conserver l'ancien comportement, définissez la variable d'environnement NODE_INVALID_UTF8 sur rien (même rien). Si la variable d'environnement est présente, elle reviendra à l'ancien comportement.

0
nbari