NodeJS捕获错误的最佳实践

我刚开始有NodeJS和Express。 来自其他stream行的脚本语言和C ++背景,asynchronous调用数据库函数有点异。 我已经整理出了一个模式,但是我仍然对捕捉exception感到好奇。 以下是我的基本模式。

var callback = function(req, res) { // do stuff connection.query(queryString, function(err,result){ if (err) throw err; // process results. }; }; var express = require('express'); var app = express(); app.get('/', callback); app.listen(3000,function() { console.log('listening'); }; 

通常我有很多的端点和callback。 我有点迷路了,我设置了try / catch块来捕获callback中抛出的错误。 我已经四处寻找一些build议,但是它们中的很多似乎都在使用web框架(如果有的话)。

当你抛出一个asynchronouscallback时,这个exception就返回到数据库事件处理程序的内部,并且你无法捕捉或处理这个exception。 所以,基本上它根本就不行。 这只会导致您放弃对该请求的处理,您将永远不会针对该请求发送回复。

基本上,你有几个如何处理错误的select。 您可以在每个端点完全处理它,并发送某种错误响应。

在每个错误点发送响应

 app.get('/', function(req, res) { // do stuff connection.query(queryString, function(err,result){ if (err) return res.status(500).send(someErrorResponse); // process results. }; }); 

转发到集中error handling程序

或者,您可以通过调用next(err)将错误转发到集中error handling程序:

 app.get('/', function(req, res, next) { // do stuff connection.query(queryString, function(err,result){ // if error, forward it on to our centralized error handler if (err) return next(err); // process results. }; }); // centralized error handler - note how it has four parameters app.use(function(err, req, res, next) { // formulate an error response here console.log(err); res.status(500).send(someErrorMessage) }); 

请参阅Nodejs处理不受支持的URL和请求types ,以获取有关在Express中使用通用error handling程序的更多信息。

使用承诺收集每个路线内的错误

如果您正在使用更多的涉及asynchronous操作的序列,而您可能会有多个asynchronous操作一起sorting,那么在每个asynchronous操作中处理错误确实会很麻烦。 这就是在所有asynchronous操作中更容易使用promise的地方,所有的错误都可以渗透到每个路由顶层的一个.catch()语句中。 你没有说你正在使用什么数据库,但这是一个想法。 总的想法是,你可以编写你的代码,这样所有的承诺拒绝(例如错误)将在每个路由处理器中传播到一个中心的.catch() ,然后你可以从.catch()调用next(err)错误集中error handling程序。 下面是一个数据库操作的最新版本的Mongoose(你没有说你正在使用哪个数据库)。

 app.get('/', function(req, res, next) { // do stuff connection.query(queryString).exec().then(function(result){ // process results. }).catch(next); }); // centralized error handler - note how it has four parameters app.use(function(err, req, res, next) { // formulate an error response here console.log(err); res.status(500).send(someErrorMessage) }); 

而且,如果您有多个操作,则显示如下:

 app.get('/', function(req, res, next) { // do stuff connection.query(queryString).exec().then(function(result){ // process results, then make another query // return the promise from this second operaton so both results // and error are chained to the first promise return connection.query(...).exec(); }).then(function(result) { // process chained result }).catch(next); }); // centralized error handler - note how it has four parameters app.use(function(err, req, res, next) { // formulate an error response here console.log(err); res.status(500).send(someErrorMessage) }); 

由于ES6支持承诺,ES7将增加对asynchronous操作(基于承诺)的asynchronous/等待支持,并且所有提供asynchronous操作的重要库已经添加或正在增加对promise的支持,显然承诺是用于pipe理asynchronous操作的语言的未来。 这将是我强烈的build议。

你永远不应该抛出这样的错误! :)原因是,在某些时候,你的整个节点应用程序将停止工作,因为一些数据库查询失败。 这应该被处理,而不是只是死。

而且因为这是一个route处理程序 – 处理用户正在获取的具体URL(例如/ ),应该有一些输出。 你总是可以显示一个状态为500的页面和一个漂亮的devise,如果有这样的错误,你不能处理,或者你可能会让你的内部状态搞砸。

所以基本上就是没有任何事情发生 – 返回任何forms的respones ,甚至render一个页面,但提供的信息出了问题。

此外,一个常见的情况就像阿隆·奥兹所提出的。 快递中的所有路线实际上都是一个中间件function,被称为一个接一个。 如果路线与请求的路线不匹配,则函数会跳过并调用下一个path。 你可以手动控制。 路由器的实际模式是这样的:

 app.get('/', function(req, res, next) { // you can have the request // you can send response like res.send('hello') // OR you can skip this function using NEXT }); 

下一个的实际签名是next(err) 。 所以如果你没有任何争论的话,它只会跳到下一个中​​间件。 如果你用一个参数来调用它,它会跳过所有常规的函数,并且转到堆栈中的最后一个函数,或者更具体地说,处理错误的函数。 他们就像普通人一样, 只是拿四个而不是三个:

 app.use(function (err, req, res, next) { }); 

理解这个函数是非常重要的 ,如果你下面的参数调用这个函数。 抛出一个错误不会有任何好处! 当然如果没有你的路线匹配的具体标准(url)最后一个将在调用将被调用,所以你仍然可以处理“找不到”的错误。

这是您将使用的常见情况:

 // development error handler, will print stacktrace if (app.get('env') === 'development') { app.use(function(err, req, res, next) { debug('ERROR [ip: %s]:: dev env -> ', req.ip, err); // I'm using debug library - very helpful res.status(err.status || 500); res.render('deverr', { // I render custom template with the whole stack beautifully displayed errMessage: err.message, error: err }); }); } // production error handler, no stacktraces leaked to user app.use(function(err, req, res, next) { res.status(err.status || 500); res.render('pages/error', { // custom error page with nice design and a message errMessage: err.message, error: {} }); }); 

希望有所帮助! 🙂

既然你使用express,它有自己的方式来处理exception,定义如下:

 function clientErrorHandler (err, req, res, next) { if (req.xhr) { res.status(500).send({ error: 'Something failed!' }) } else { next(err) } } app.use(clientErrorHandler) 

欲了解更多信息:

https://expressjs.com/en/guide/error-handling.html