【问题标题】:Node Exits when DB error caught and re-thrown in Express Application在 Express 应用程序中捕获并重新抛出 DB 错误时节点退出
【发布时间】:2016-04-13 11:37:51
【问题描述】:

以下代码位于 express 4.0 路由器中。我故意给出了错误的 SELECT 语句(表不存在)。 clientErrorHandler() 按预期调用,然后节点退出(崩溃)。 由于数据库调用的异步性质,添加 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(),这也是预期的行为并且节点不会退出。这表明节点没有因为 DB 异常而崩溃。

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

谢谢。

【问题讨论】:

    标签: mysql node.js express


    【解决方案1】:

    也许您应该阅读更多关于 JavaScript 和回调的信息,因为您的 res.send 不在回调范围内。

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

    1. DBCon.DBConUtil.pool.getConnection
    2. 回复.发送
    3. JSON.stringify(带有未定义的属性)
    4. connection.query
    5. logger.info
    6. connection.release

    以下两种方法中的任何一种都可以解决它:
    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!

    【讨论】:

    • 嗨,两种解决方案都没有帮助。当抛出回调方法但随后退出时,Node 能够捕获异常。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-30
    • 2012-10-17
    • 2014-08-08
    • 1970-01-01
    相关资源
    最近更新 更多