error handling in asynchronous node.js calls

前端 未结 10 1623
感动是毒
感动是毒 2020-12-12 19:32

I\'m new to node.js although I\'m pretty familiar with JavaScript in general. My question is regarding \"best practices\" on how to handle errors in node.js.

Normall

相关标签:
10条回答
  • 2020-12-12 19:58

    Checkout the uncaughtException handler in node.js. It captures the thrown errors that bubble up to the event loop.

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

    But not throwing errors is always a better solution. You could just do a return res.end('Unabled to load file xxx');

    0 讨论(0)
  • 2020-12-12 19:58

    Also in synchronous multi-threaded programming (e.g. .NET, Java, PHP) you can't return any meaningful information to the client when a custom unkown Exception is caught. You may just return HTTP 500 when you have no info regarding the Exception.

    Thus, the 'secret' lies in filling a descriptive Error object, this way your error handler can map from the meaningful error to the right HTTP status + optionally a descriptive result. However you must also catch the exception before it arrives to process.on('uncaughtException'):

    Step1: Define a meaningful error object

    function appError(errorCode, description, isOperational) {
        Error.call(this);
        Error.captureStackTrace(this);
        this.errorCode = errorCode;
        //...other properties assigned here
    };
    
    appError.prototype.__proto__ = Error.prototype;
    module.exports.appError = appError;
    

    Step2: When throwing an Exception, fill it with properties (see step 1) that allows the handler to convert it to meannigul HTTP result:

    throw new appError(errorManagement.commonErrors.resourceNotFound, "further explanation", true)
    

    Step3: When invoking some potentially dangerous code, catch errors and re-throw that error while filling additional contextual properties within the Error object

    Step4: You must catch the exception during the request handling. This is easier if you use some leading promises library (BlueBird is great) which allows you to catch async errors. If you can't use promises than any built-in NODE library will return errors in callback.

    Step5: Now that your error is caught and contains descriptive information about what happens, you only need to map it to meaningful HTTP response. The nice part here is that you may have a centralized, single error handler that gets all the errors and map these to HTTP response:

        //this specific example is using Express framework
        res.status(getErrorHTTPCode(error))
    function getErrorHTTPCode(error)
    {
        if(error.errorCode == commonErrors.InvalidInput)
            return 400;
        else if...
    }
    

    You may other related best practices here

    0 讨论(0)
  • 2020-12-12 20:04

    Very good question. I'm dealing with the same problem now. Probably the best way, would be to use uncaughtException. The reference to respone and request objects is not the problem, because you can wrap them into your exception object, that is passed to uncaughtException event. Something like this:

    var HttpException = function (request, response, message, code) {
    
      this.request = request;
      this.response = response;  
      this.message = message;    
      this.code = code || 500;
    
    }
    

    Throw it:

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

    And handle the response:

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

    I haven't test this solution yet, but I don't see the reason why this couldn't work.

    0 讨论(0)
  • 2020-12-12 20:04

    I've recently created a simple abstraction named WaitFor to call async functions in sync mode (based on Fibers): https://github.com/luciotato/waitfor

    It's too new to be "rock solid".

    using wait.for you can use async function as if they were sync, without blocking node's event loop. It's almost the same you're used to:

    var wait=require('wait.for');
    
    function handleRequest(request, response) {
          //launch fiber, keep node spinning
          wait.launchFiber(handleinFiber,request, response); 
    }
    
    function handleInFiber(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, callback) {
      if (something) 
        throw new Error("something bad happened");
      Response.end("OK");
    }
    

    Since you're in a fiber, you can program sequentially, "blocking the fiber", but not node's event loop.

    The other example:

    var sys    = require('sys'),
        fs     = require('fs'),
        wait   = require('wait.for');
    
    require("http").createServer( function(req,res){
          wait.launchFiber(handleRequest,req,res) //handle in a fiber
      ).listen(8124);
    
    function handleRequest(request, response) {
      try {
        var fd=wait.for(fs.open,"/proc/cpuinfo", "r");
        console.log("File open.");
        var buffer = new require('buffer').Buffer(10);
    
        var bytesRead=wait.for(fs.read,fd, buffer, 0, 10, null);
    
        buffer.dontTryThisAtHome();  // causes exception
    
        response.end(buffer);
      }
      catch(err) {
        response.end('ERROR: '+err.message);
      }
    
    }
    

    As you can see, I used wait.for to call node's async functions in sync mode, without (visible) callbacks, so I can have all the code inside one try-catch block.

    wait.for will throw an exception if any of the async functions returns err!==null

    more info at https://github.com/luciotato/waitfor

    0 讨论(0)
提交回复
热议问题