下面是我用来处理/记录 Express 应用程序中所有可能的异常的方法。还有什么办法吗?
错误处理是一个微妙的问题,尤其是在处理 Express 时。让我们从最简单的场景开始。想象一下我们的应用程序如下:
console.log(ciao.ciao); // EEERRROOORRR
从控制台启动应用程序,我们得到以下信息:
console.log(ciao.ciao);
^
ReferenceError: ciao is not defined
请注意,上述情况是一个未捕获异常的示例,因为我们没有因错误而执行编写的代码。要处理上述错误,我们可以执行以下操作:
process.on('uncaughtException', function (err) {
console.log('error', ' * we did it, we handled the error * ', err.stack.trim());
process.exit(1);
});
console.log(ciao.ciao); // EEERRROOORRR
如果我们现在启动我们得到的应用程序:
error * we did it, we handled the error * ReferenceError: ciao is not defined
请注意!!!"process.on('uncaughtException'..." 将被弃用!!!
为了在弃用发生时做好准备,我们最好使用我们最喜欢的记录器的异常处理程序,它是强大且超受欢迎的winston。我们的应用程序变为:
var winston = require('winston');
var logger = new (winston.Logger)({
transports: [
new (winston.transports.Console)({ handleExceptions: true }),
]
});
console.log(ciao.ciao); // EEERRROOORRR
它的输出如下:
error: uncaughtException: ciao is not defined date=Wed Oct 22 2014 16:26:53 GMT+0200 (ora legale Europa occidentale), pid=8052, uid=null, gid=null, cwd=c:\Projects\Eclipse\WEBSITE\node_taxiapplication, execPath=C:\Program Files\nodejs\node.exe, version=v0.10.26, argv=[node, c:\Projects\Eclipse\WEBSI
TE\node_taxiapplication\test2.js], rss=13479936, heapTotal=7130752, heapUsed=2760024, loadavg=[0, 0, 0],...
伟大的winston输出了很多有意义的信息来帮助我们管理错误,看看pid参数或者内存信息(rss,heapTotal,...)。winston 所做的另一件好事是退出应用程序,这在未捕获异常的情况下非常有用。
让我们的应用程序成为 Express Server 我们的应用程序变成:
var winston = require('winston');
var express = require('express');
var app = express();
var logger = new (winston.Logger)({
transports: [
new (winston.transports.Console)({ handleExceptions: true }),
]
});
app.get('/', function(req, res, next) {
console.log(ciao.ciao); // EEERRROOORRR
});
app.listen(3000);
启动服务器并询问http://localhost:3000
我们在浏览器上的浏览器:
ReferenceError: ciao is not defined at Object.handle (c:\Projects\Eclipse\WEBSITE\node_taxiapplicatio...
并且它仍在运行的应用程序在 Web 服务器上出现错误时不是一个好主意。
温斯顿异常处理程序到底在哪里?
Winston 没有处理上述错误,因为它已由 Express 处理,这是因为该错误在以下 Express 路由处理程序的范围内:
function(req, res, next) {
console.log(ciao.ciao); // EEERRROOORRR
});
So winston is out of the game in case of error inside of an Express route handler
我们想要实现的是使用 winston 记录这个错误并退出应用程序,但是为了达到我们的目标,我们需要在 Express “内部”发生错误时执行我们的代码。为此,我们将使用 Express 错误中间件,如下所示:
var winston = require('winston');
var express = require('express');
var app = express();
var logger = new (winston.Logger)({
transports: [
new (winston.transports.Console)({ handleExceptions: true }),
]
});
app.get('/', function(req, res, next) {
console.log(ciao.ciao); // EEERRROOORRR
});
app.use(function(err, req, res, next) {
logger.log('error', ' * logged by winston * ', err.stack.trim());
process.exit(1);
});
app.listen(3000);
如果我们向浏览器询问,http://localhost:3000
我们会得到应用程序退出,并且在控制台上我们会得到以下由 winston 抛出的信息:
error: * logged by winston * ReferenceError: ciao is not defined
不幸的是,在这种情况下,我们无法获得当 winston 直接处理异常时输出的所有信息,但在列表中,我们也可以控制 Express 处理的错误。
但是我想要winston直接处理异常时给出的所有信息
好的,让我们试试吧!我们必须想办法让 Express 失去对 Exception 的控制。我们在上面说过,当这些异常发生在路由处理程序的范围内时,Express 会处理这些异常:
app.get('/', function(req, res, next) {
console.log(ciao.ciao);
});
让我们检查一下当错误发生在 Express 路由处理程序中包含的异步函数中时会发生什么:
app.get('/', function(req, res, next) {
setTimeout(function () {
console.log(ciao.ciao);
});
});
启动应用程序:
var winston = require('winston');
var express = require('express');
var app = express();
var logger = new (winston.Logger)({
transports: [ new (winston.transports.Console)({ handleExceptions: true }) ]
});
app.get('/', function(req, res, next) {
setTimeout(function () {
console.log(ciao.ciao); // EEERRROOORRR
}, 1);
});
app.listen(3000);
并要求http://localhost:3000
我们观察应用程序退出并在控制台上:
error: uncaughtException: ciao is not defined date=Thu Oct 23 2014 09:52:01 GMT+0200 (ora legale Europa occidentale), pid=5952, uid=null, gid=null, cwd=c:\Projects\Eclipse\WEBSITE\node_taxiapplication, execPath=C:\Program Files\nodejs\node.exe, version=v0.10.26, argv=[node, c:\Projects\Eclipse\WEBSI
TE\node_taxiapplication\test2.js], rss=18325504, heapTotal=15453568, heapUsed=4883192,
嘿,Express 没有处理上述错误,但 winston 处理了(我们在输出中有内存详细信息)。这是因为错误没有发生在 Express 范围内,而是发生在异步函数范围内。因此,我们需要将 Express 范围内的错误转换为异步函数范围内的错误。我们可以做到这一点,事实上我们已经能够运行我们的代码来管理 Express 错误。我们的策略是在 Express 错误中间件(其中有我们处理 Express 错误的代码)和 setTimeout 中插入一个异步 setTimeout(1ms 延迟),以将到达中间件的相同错误作为参数抛出。
var winston = require('winston');
var express = require('express');
var app = express();
var logger = new (winston.Logger)({
transports: [ new (winston.transports.Console)({ handleExceptions: true }) ]
});
app.get('/', function(req, res, next) {
console.log(ciao.ciao); // EEERRROOORRR
});
app.use(function(err, req, res, next) {
res.send('Arrrghhh!!! The Server is at the moment down.');
setTimeout(function () {
throw new Error(err.stack.trim()); // <<<--- TRICK
}, 1);
});
app.listen(3000);
请求http://localhost:3000
我们在浏览器上得到响应“Arrrghhh !!!...”,应用程序退出并在我们获得的控制台上:
error: uncaughtException: ReferenceError: ciao is not defined date=Thu Oct 23 2014 10:00:51 GMT+0200 (ora legale Europa occidentale), pid=5792, uid=null, gid=null, cwd=c:\Projects\Eclipse\WEBSITE\node_taxiapplication, execPath=C:\Program Files\nodejs\node.exe, version=v0.10.26, argv=[node, c:\Projec
ts\Eclipse\WEBSITE\node_taxiapplication\test2.js], rss=18489344, heapTotal=15453568, heapUsed=5115092,...
我们发现所有错误都通过winston记录/管理:应用程序退出并且错误日志包含许多有助于解决问题的有用信息。