Express 框架中对错误的统一处理

 2016年04月12日    459     声明


在Node.js中无法使用try/catch处理异步回调函数中的异常。对于异步异常,Node提供了两种处理方式:callback回调、'error'事件。而在Express框架中,基于回调传递错误及错误处理中间件,可以捕获系统中所有异步异常并进行统一处理。


  1. next()方法与错误传递
  2. 使用中间处理错误

1. next()方法与错误传递

Express是一个Web框架,它对Node的HTTP核心模块中对象进行了扩展,提供了更方便的HTTP请求与响应处理方式。在Express中进行错误处理时,首先要使用next()方法将错误向下传递。

next()app.METHOD()router.METHOD()方法回调函数中的第三个参数。通过next()方法,可以将请求定向到下一个处理函数或另一个路由中,next()方法也可以用于传递错误。

在HTTP请求中,我们可能会使用next()方法传递一个状态或错误:

传递一个HTTP状态

对于不存在的某一个或某一类路由,可以使用next()方法传递一个404状态:

router.all('/user/*', function(req, res, next){
  next(404);
});

当出现异常时,可以使用next()方法传递一个500状态:

router.get('/a/path', function(req, res, next){
  fs.readFile('a/file', function(err, data){
    if(err){
      // 打印一个标准错误,并使用next()方法传递一个500状态
      console.error(err);
      next(500);
    } else {
      res.send('一些响应信息');
    }
  });
});


传递错误信息

请求处理过程中出错时,也可以使用next()方法直接传递这个错误:

router.get('/a/path', function(req, res, next){
  fs.readFile('a/file', function(err, data){
    if(err){
      // 使用next()方法传递错误信息
      next(err);
    } else {
      res.send('一些响应信息');
    }
  });
});

使用Promise进行异步处理时,也可以通过next()方法传递出现的异常:

router.get('/a/path', function(req, res, next){
  promise.then(function(result) {
    // 操作成功
    res.send('一些响应信息');
  }).catch(function(err) {
    // 操作失败,使用next()方法传递错误信息
    next(err);
  });
});


2. 使用中间处理错误

Express中的中间件分为两类:通过router.use()方法挂载的路由中间件和通过app.use()方法挂载的应用中间件,前者只对某一个或一类路由起做用,而后者会在应用范围内起作用。

处理异常时,一般会在全局处理。在app.js文件中,Express提供了以下处理异常的中间件:

// 捕获404并定向到错误处理
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// 错误处理

// 开发环境下的错误处理
// 会输出堆栈信息
if (app.get('env') === 'development') {
  app.use(function(err, req, res, next) {
    // 设置响应状态
    res.status(err.status || 500); 
    // 渲染错误处理页
    res.render('error', {
      message: err.message,
      error: err,
      layout: false
    });
  });
}

// 生产环境下的错误处理
// 不会向用户显示堆栈信息
app.use(function(err, req, res, next) {
  // 设置响应状态
  res.status(err.status || 500);
  // 渲染错误处理页
  res.render('error', {
    message: err.message,
    error: {},
    layout: false
  });
});

对于定义的路由,都会由上面第一个中间件捕获,在这里会生成一个404的错误,并将错误向下传递到错误处理路由。

Express提供了两个错误中间件(处理程序),分别用于开发/生产两种模式下的错误处理。在开发模式下,我们一般会输出错误的堆栈信息,以方便调试。而在生产模式下,一般会显示一个错误提示页(如:404-页面未找到、500-服务器内部错误等)。只需要在这两个中间件中渲染不同的页面,就可以实现在不同环境下,对不同错误的统一响应和处理。