Express 错误处理
Node.js中无法使用try/catch处理异步回调函数中的异常。在别的编程语言中,常用try/catch
捕获异常。但是在node中,最外层的try/catch
, 不能捕获到异步回调函数的异常,可以认为他们不是一个位面的东西。但是try/catch
可以捕获一些非异步异常,如
try{
var result = JSON.parse({status: 'ok'});
} catch (err) {
console.log(err);
}
对于异步异常,Node提供了两种处理方式:callback回调、'error'事件。而在Express框架中,基于回调传递错误及错误处理中间件,可以捕获系统中所有异步异常并进行统一处理。
next()方法与错误传递
Express是一个Web框架,它对Node的HTTP核心模块中对象进行了扩展,提供了更方便的HTTP请求与响应处理方式。在Express中进行错误处理时,首先要使用next()方法将错误向下传递。
next()
是app.method()
或router.method()
方法回调函数中的第三个参数。通过next()
方法,可以讲请求定向到下一个处理函数或另一个路由中,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.log(err);
next(500);
} else {
res.send('some info');
}
});
} )
传递错误信息
请求处理过程中出错时,也可以使用next()
方法直接传递这个错误:
router.get('/a/path', funciton (req, res, next) {
fs.readFile('a/file', function (err, data) {
if (err) {
// 使用 next() 方法传递错误信息
next(err);
} else {
res.send('some info');
}
})
})
使用promise进行一步处理时,也可以通过next()
方法传递出现的异常:
router.get('/a/path', function (req, res, next) {
promise.then(function (result) {
res.send('some info');
}).catch(function (err) {
next(err);
});
})
使用中间件处理错误
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-服务器内部错误等)。只需要在这两个中间件中渲染不同的页面,就可以实现在不同环境下,对不同错误的统一响应和处理。
全局错误处理
uncaughtException
uncaughtException
事件是在程序中有为捕获的错误时触发。默认情况下,node.js在遇到未捕获的错误是,会通过将堆栈跟踪打印到STDRR,并以错误码1退出。uncaughtException
将会覆盖默认行为,并以错误码0退出。
process.on('uncaughtException', (err) => {
console.error('process uncaughtException:', err)
})
throw new Error('sssss')
// 打印 process uncaughtException: Error: sssss, 然后退出程序
uncaughtException
的设计初衷是让开发者捕获没有记录的错误,然后记录问题。而不是在发现错误之后重启服务。在发现错误最好的方法是解决bug,重新上线。
unhandledRejection
unhandledRejection
和 uncaughtException
类似。在系统没有捕获到promise的reject状态时,会触发此事件。与uncaughtException
不同的在于,unhandledRejection
的错误不会让程序退出。
process.on('unhandledRejection', (reason, promise) => {
console.error('process unhandledRejection:', reason)
})