J'utilise node.js avec socket.io pour donner à ma page Web un accès aux données de caractères servies par un socket TCP. Je suis assez nouveau pour node.js.
Utilisateur ----> Page Web <- (socket.io) -> node.js <- (TCP) -> TCP Serveur
Le code est heureusement bref:
io.on('connection', function (webSocket) {
tcpConnection = net.connect(5558, 'localhost', function() {});
tcpConnection.on('error', function(error) {
webSocket.emit('error', error);
tcpConnection.close();
});
tcpConnection.on('data', function(tcpData) {
webSocket.emit('data', { data: String.fromCharCode.apply(null, new Uint8Array(tcpData))});
});
});
Tout fonctionne parfaitement dans le cas normal, mais je ne peux pas garantir que le serveur TCP sera présent tout le temps. Si ce n'est pas le cas, la pile TCP renvoie ECONNREFUSED à node.js - c'est tout à fait prévu et je dois le gérer avec élégance. Actuellement, je vois:
events.js:72
throw er; // Unhandled 'error' event
^
Error: connect ECONNREFUSED
at errnoException (net.js:904:11)
at Object.afterConnect [as oncomplete] (net.js:895:19)
... et tout le processus se termine.
J'ai beaucoup cherché des solutions à cela; la plupart des hits semblent provenir de programmeurs qui demandent pourquoi ECONNREFUSED est reçu - et le conseil est simplement de s'assurer que le serveur TCP est disponible. Pas de discussion sur le traitement des cas d'échec.
Cet article - Node.js connectListener continue d'appeler l'erreur de socket - suggère d'ajouter un gestionnaire pour l'événement 'error' comme je l'ai fait dans le code ci-dessus. C’est exactement ce que je voudrais que cela fonctionne ... sauf que ce n’est pas (pour moi), mon programme ne piège pas ECONNREFUSED.
J'ai essayé de RTFM, et les documents node.js à http://nodejs.org/api/net.html#net_event_error_1 suggèrent qu'il y a bien un événement 'error' - mais donne peu d'indices pour savoir comment utilise le.
Les réponses à d'autres SO publications similaires (telles que Erreur Node.js: connect ECONNREFUSED ) conseillent un gestionnaire d'exception non capturé global, mais cela me semble une mauvaise solution. Ce n'est pas mon programme qui jette une exception à cause d'un code incorrect, il fonctionne bien - il est supposé gérer les défaillances externes comme prévu.
Alors
Oh et:
$ node -v
v0.10.31
J'ai couru le code suivant:
var net = require('net');
var client = net.connect(5558, 'localhost', function() {
console.log("bla");
});
client.on('error', function(ex) {
console.log("handled error");
console.log(ex);
});
Comme je n'ai pas ouvert 5558, le résultat était:
$ node test.js
handled error
{ [Error: connect ECONNREFUSED]
code: 'ECONNREFUSED',
errno: 'ECONNREFUSED',
syscall: 'connect' }
Cela prouve que l'erreur est traitée correctement… ce qui suggère que l'erreur se produit ailleurs.
Comme discuté dans une autre réponse, le problème est en réalité cette ligne:
webSocket.emit('error', error);
L'événement 'erreur' est spécial et doit être géré quelque part (si ce n'est pas le cas, le processus se termine).
Si vous renommez simplement l'événement en 'problème' ou 'avertissement', l'intégralité de l'objet d'erreur sera retransmise via la socket socket.io jusqu'à la page Web:
webSocket.emit('warning', error);
La seule façon pour moi de résoudre ce problème consiste à envelopper le contenu net dans un domaine:
const domain = require('domain');
const net = require('net');
const d = domain.create();
d.on('error', (domainErr) => {
console.log(domainErr.message);
});
d.run(() => {
const client = net.createConnection(options, () => {
client.on('error', (err) => {
throw err;
});
client.write(...);
client.on('data', (data) => {
...
});
});
});
L'erreur de domaine capture les conditions d'erreur qui se sont produites avant la création du client Web, telles qu'un hôte non valide.
Voir aussi: https://nodejs.org/api/domain.html