节点在Express Application中捕获并重新引发数据库错误时退出

时间:2016-04-13 11:37:51

标签: mysql node.js express

下面的代码是在一个Express 4.0路由器中。我故意给出了一个错误的SELECT语句(表不存在)。 clientErrorHandler()按预期调用,然后Node退出(崩溃)。 由于DB调用的异步性质,添加try / catch没有帮助。 当我纠正SELECT语句时,一切都按预期工作。

router.use(function (req, res, next){
  DBCon.DBConUtil.pool.getConnection(function(err, connection){
    if (err) throw new DBDataError("Error while getting connection from pool");
    connection.query('SELECT * FROM employee' ,function(err,rows){
      if(err){
        connection.release();
        throw new DBDataError("Error while executing select statement using pool connection.");
      }else{
        res.rows1 = rows;
        logger.info("App-Instance-name: %s, filename: %s, MessageContent: %s", process.env.NODE_APP_INSTANCE, __filename, JSON.stringify({message: "Data received from Db using connection pool: ", data: rows}));
        connection.release();
      }
    });
  });
  res.send(JSON.stringify(res.rows1));
  //next();
});

router.use(clientErrorHandler);
router.use(errorHandler);

function clientErrorHandler(err, req, res, next) {
  logger.info("App-Instance-name: %s, filename: %s, Cookies: %s", process.env.NODE_APP_INSTANCE, __filename, JSON.stringify(req.cookies));
  logger.info("App-Instance-name: %s, filename: %s, stack trace: ", process.env.NODE_APP_INSTANCE, __filename, err.stack);
  return next(err);
}

function errorHandler(err, req, res, next) {
  res.status(500);
  res.send('Error in handing DB calls.');
}

function DBDataError(message) {
  this.constructor.prototype.__proto__ = Error.prototype
  Error.captureStackTrace(this, this.constructor)
  this.name = this.constructor.name
  this.message = message
}

另外两个信息: -

(1)如果在“if(err)”之外没有实际DB错误时抛出相同的DBDataError,则会按预期调用clientErrorHandler(),并且节点不会退出。这表明脚本能够按预期抛出并捕获错误。

(2)如果使用“if(err)”捕获DB错误并且我没有抛出新的DBDataError,则不会调用clientErrorHandler(),这也是预期的行为,节点不会退出。这表明由于数据库异常,节点没有崩溃。

任何专家都可以对此有所了解。

感谢。

1 个答案:

答案 0 :(得分:0)

也许你应该多读一些关于JavaScript和回调的信息,因为你的res.send不在回调中。

调用的函数的顺序(在router.use回调开始之后),假设是非错误流

  1. DBCon.DBConUtil.pool.getConnection
  2. res.send
  3. JSON.stringify(具有未定义的属性)
  4. connection.query
  5. logger.info
  6. connection.release
  7. 以下任何一项都应该解决它:
    1:

    router.use(function (req, res, next){
      DBCon.DBConUtil.pool.getConnection(function(err, connection){
        if (err) throw new DBDataError("Error while getting connection from pool");
        connection.query('SELECT * FROM employee' ,function(err,rows){
          if(err){
            connection.release();
            throw new DBDataError("Error while executing select statement using pool connection.");
            res.send(JSON.stringify({error: 'DB error'}));
          }else{
            res.rows1 = rows;
            logger.info("App-Instance-name: %s, filename: %s, MessageContent: %s", process.env.NODE_APP_INSTANCE, __filename, JSON.stringify({message: "Data received from Db using connection pool: ", data: rows}));
            connection.release();
            res.send(JSON.stringify(res.rows1));
          }
        });
      });
      //next();
    });
    

    2(更好的一个):

    router.use(function (req, res, next){
      DBCon.DBConUtil.pool.getConnection(function(err, connection){
        if (err) throw new DBDataError("Error while getting connection from pool");
        connection.query('SELECT * FROM employee' ,function(err,rows){
          if(err){
            connection.release();
            throw new DBDataError("Error while executing select statement using pool connection.");
          }else{
            res.rows1 = rows;
            logger.info("App-Instance-name: %s, filename: %s, MessageContent: %s", process.env.NODE_APP_INSTANCE, __filename, JSON.stringify({message: "Data received from Db using connection pool: ", data: rows}));
            connection.release();
          }
          // Let express know this callback is done and it can resume the middleware process
          next();
        });
      });
    });
    

    最后注意:请不要在中间件中使用res.send!