45 votes

traitement des erreurs dans les appels asynchrones de node.js

Je suis nouveau sur node.js même si je suis assez familier avec JavaScript en général. Ma question est à propos des "meilleures pratiques" sur la façon de gérer les erreurs dans node.js.

Normalement lors de la programmation de serveurs web, des serveurs FastCGI ou des pages web dans différentes langues, je suis en utilisant les Exceptions avec le blocage des gestionnaires dans un multi-threading de l'environnement. Lorsqu'une demande arrive j'ai l'habitude de faire quelque chose comme ceci:

function handleRequest(request, response) {
  try {

    if (request.url=="whatever")
      handleWhateverRequest(request, response);
    else
      throw new Error("404 not found");

  } catch (e) {
    response.writeHead(500, {'Content-Type': 'text/plain'});
    response.end("Server error: "+e.message);
  }
}

function handleWhateverRequest(request, response) {
  if (something) 
    throw new Error("something bad happened");
  Response.end("OK");
}

De cette façon, je peux toujours gérer les erreurs internes et envoyer une réponse valide à l'utilisateur.

Je comprends que le node.js on est censé faire des appels non bloquants qui conduit évidemment à divers nombre de rappels, comme dans cet exemple:

var sys    = require('sys'),
    fs     = require('fs');

require("http").createServer(handleRequest).listen(8124);

function handleRequest(request, response) {

  fs.open("/proc/cpuinfo", "r",
    function(error, fd) {
      if (error)
        throw new Error("fs.open error: "+error.message);

      console.log("File open.");

      var buffer = new require('buffer').Buffer(10);
      fs.read(fd, buffer, 0, 10, null,
        function(error, bytesRead, buffer) {

          buffer.dontTryThisAtHome();  // causes exception

          response.end(buffer);
        }); //fs.read

    }); //fs.open

}

Cet exemple va tuer complètement le serveur car les exceptions ne sont pas interceptés. Mon problème est que je ne peux pas utiliser un seul try/catch plus et ne peut donc pas généralement attraper toute erreur qui pourrait être soulevée au cours du traitement de la demande.

Bien sûr, je pourrais ajouter un try/catch dans chaque rappel mais je n'aime pas cette approche car ensuite, c'est au programmeur de ne pas oublier un try/catch. Pour un serveur complexe avec beaucoup de différentes et complexes gestionnaires ce n'est pas acceptable.

Je pourrais utiliser un gestionnaire global d'exception (la prévention de la compléter crash du serveur), mais je ne peux pas envoyer une réponse à l'utilisateur, car je ne sais pas qui demande de mener à l'exception. Cela signifie également que la demande reste non gérée/open et le navigateur attend toujours une réponse.

Quelqu'un avoir un bon, solide comme le roc de la solution?

13voto

Sam Shiles Points 3254

Nœud de 0,8 introduit un nouveau concept appelé "Domaines". Ils sont très grossièrement analogousness de domaines d'application dans .net et de fournir un moyen d'encapsuler un groupe d'opérations d'e / s. En gros, ils vous permettent d'envelopper votre demande de traitement des appels dans un contexte spécifique du groupe. Si ce groupe lève toutes les exceptions non traitées, puis ils peuvent être manipulés et traités d'une manière qui vous donne accès à tous la portée et le contexte spécifique de l'information vous avez besoin pour réussir à récupérer à partir de l'erreur (si possible).

Cette fonctionnalité est nouvelle et vient tout juste d'être présenté, donc à utiliser avec précaution, mais de ce que je peux dire qu'il a été spécifiquement mises en place pour résoudre le problème qui l'OP est d'essayer de lutter contre.

La Documentation peut être trouvé à: http://nodejs.org/api/domain.html

5voto

3rdEden Points 2697

Vérifiez le gestionnaire uncaughtException dans node.js. Il capture les erreurs renvoyées qui remontent jusqu'à la boucle d'événement.

http://nodejs.org/docs/v0.4.7/api/process.html#event_uncaughtException_

Mais ne pas jeter d'erreurs est toujours une meilleure solution. Vous pouvez juste faire un return res.end('Unabled to load file xxx');

5voto

chjj Points 5676

C'est l'un des problèmes avec le Nœud à l'instant. Il est pratiquement impossible de retracer qui demande a provoqué une erreur d'être jeté à l'intérieur d'un rappel.

Vous allez devoir gérer vos erreurs dans les rappels eux-mêmes (où vous avez encore une référence pour les objets request et response), si possible. Le uncaughtException gestionnaire d'arrêter le nœud du processus de sortie, mais la demande qui a provoqué l'exception à la première place pendre juste là, à partir du point de vue des utilisateurs.

3voto

Udo G Points 2254

J'ai une réponse à ma propre question... :)

Comme il semble y avoir aucun moyen de contourner manuellement la capture des erreurs. Je vais maintenant utiliser une fonction d'assistance qui lui-même renvoie à une fonction contenant un bloc try/catch. En outre, mon propre serveur web de classe vérifie si le traitement de la demande d'appels de fonction response.end() ou le try/catch fonction d'assistance waitfor() (levant une exception dans le cas contraire). Cela évite en grande partie à cette demande sont, à tort, à gauche non protégé par le développeur. Il n'est pas à 100% le risque d'erreur de solution, mais fonctionne assez bien pour moi.

handler.waitfor = function(callback) {
  var me=this;

  // avoid exception because response.end() won't be called immediately:
  this.waiting=true;

  return function() {
    me.waiting=false;
    try {
      callback.apply(this, arguments);

      if (!me.waiting && !me.finished)
        throw new Error("Response handler returned and did neither send a "+
          "response nor did it call waitfor()");

    } catch (e) {
      me.handleException(e);
    }
  }
}

De cette façon, j'ai juste à ajouter un inline waitfor() appel à être sur le côté sécuritaire.

function handleRequest(request, response, handler) {
  fs.read(fd, buffer, 0, 10, null, handler.waitfor(
    function(error, bytesRead, buffer) {

      buffer.unknownFunction();  // causes exception
      response.end(buffer);
    }
  )); //fs.read
}

La vérification réelle mécanisme est un peu plus complexe, mais il doit être clair comment il fonctionne. Si quelqu'un est intéressé, je peux poster le code complet ici.

3voto

Marian Galik Points 454

Très bonne question. Je fais face au même problème maintenant. Probablement la meilleure façon, serait d'utiliser des uncaughtException. La référence à respone et les objets de requête n'est pas le problème, parce que vous pouvez intégrer dans votre objet d'exception, qui est passé de uncaughtException événement. Quelque chose comme ceci:

var HttpException = function (request, response, message, code) {

  this.request = request;
  this.response = response;  
  this.message = message;    
  this.code = code || 500;

}

Jeter:

throw new HttpException(request, response, 'File not found', 404);

Et gérer la réponse:

process.on('uncaughtException', function (exception) {
  exception.response.writeHead(exception.code, {'Content-Type': 'text/html'});
  exception.response.end('Error ' + exception.code + ' - ' + exception.message);
});

Je n'ai pas tester cette solution, mais je ne vois pas pourquoi cela ne pouvait pas fonctionner.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X