自定义错误在throw语句或next()调用中不能正确传播

我正在开发一个Node.js / CoffeeScript应用程序,我正在使用类层次结构的错误。 当我在路由处理程序的根中使用throw语句时,一切正常。

 class APIError extends Error constructor: -> app.error (err, req, res, next) -> if err instance of APIError console.log 'APIError captured' app.get '/', (req, res, next) -> throw new APIError 

但是,在Mongoose中,在callback函数中使用throw语句:

 app.get '/', (req, res, next) -> UserModel.where('name', 'Joe').findOne (err, doc) -> throw new APIError 

结果是

 /usr/local/lib/node_modules/mongoose/lib/utils.js:413 throw err; ^ Error: 

当我调用next()而不是,如

 app.get '/', (req, res, next) -> UserModel.where('name', 'Joe').findOne (err, doc) -> return next new APIError 

甚至可以在处理程序的主体中使用它:

 app.get '/', (req, res, next) -> next new APIError 

我得到undefined被打印出来在控制台。

更改最后一条语句return next Error一条return next Error按预期工作,即在控制台中打印出exception堆栈跟踪:

 app.get '/', (req, res, next) -> return next Error 'This works as expected' 

是Node.js问题还是我在CoffeeScript中定义类的方式? 任何想法如何使这样的错误层次工作?

更新1

我可以确认这是CoffeeScript的类实现的方式。 使用标准的JS原型链定义解决了这个问题,但是它并不正确。

在其构造函数中设置类的name属性可以解决问题(第3行):

 class APIError extends Error constructor: -> @name = 'APIError' app.use (err, req, res, next) -> if err instance of APIError console.log 'Error captured' app.get '/', (req, res, next) -> #This will work: captured by error handler throw new APIError app.get '/in-mongoose-callback', (req, res, next) -> UserModel.where('name', 'Joe').findOne (err, doc) -> #This one works as expected: captured by error handler return next new APIError 

这是由于CoffeeScript 1.3.3(2012年5月15日) 发生的变化之一 :

由于JavaScript严格模式的新语义,CoffeeScript不再保证构造函数在所有运行时都有名称。 见#2052讨论。

请注意,在Mongoose查询callback中使用throw语句而不是next() 将不起作用

很难说,但是直到我们将它们移动到服务器脚本的末尾,即使在启动服务器之后,我们也遇到了错误。 这是使用快递与节点,但可以给你一个提示。 在我们接近开始的服务器文件之前,假设没有问题,但在我们将所有的error handling结束之后开始工作。 不确定路由器或中间件的操作框架顺序问题,但似乎解决了我们的问题。


 ///////////////////////////// // Start Server ///////////////////////////// app.listen(siteConf.port); ////////////////////////// // Error Handling ////////////////////////// function NotFoundError(req, message){ this.name = "NotFoundError"; this.status = 404; this.message = message || (req.method + " " + req.url + " could not be found"); Error.captureStackTrace(this, NotFoundError); } NotFoundError.prototype.__proto__ = Error.prototype; function ProtectedResourceError(req, message){ this.name = "ProtectedResourceError"; this.status = 401; this.message = message || (req.url + " is protected"); } ProtectedResourceError.prototype.__proto__ = Error.prototype; function ValidationError(req, message, errors){ this.name = "ValidationError"; this.status = 400; this.message = message || ("Error when validating input for " + req.url); this.errors = errors; } ValidationError.prototype.__proto__ = Error.prototype; function SearchError(req, message){ this.name = "SearchError"; this.status = 400; this.message = message || ("Error when searching"); } SearchError.prototype.__proto__ = Error.prototype; // If no route matches, throw NotFoundError app.use(function(req, res, next) { console.log("No matching route for " + req.url); next(new NotFoundError(req)); }); // General error handler app.use(function(err, req, res, next) { //console.log("Trapped error : " + err); // handle exceptions if (err instanceof ValidationError) { standardResponse(req, res, {error: err.message, fields: err.errors}, err.status, err.message); } else if (err instanceof ProtectedResourceError) { standardResponse(req, res, {error: err.message}, err.status, err.message); } else if (err instanceof NotFoundError) { standardResponse(req, res, {error: err.message}, err.status, err.message); } else if (err instanceof SearchError) { standardResponse(req, res, {error: err.message}, err.status, err.message); } else { standardResponse(req, res, {error: err.message}, 500, err.message); } }); 

在使用express时,我扩展了Error,将名称设置为原型属性,并执行堆栈跟踪。

 class RequestError extends Error name: 'RequestError' constructor:(@status, message)-> super message Error.captureStackTrace @, @constructor 

我可以做new RequestError 403, 'Invalid username/password.' 对于不好的用户login,或者new RequestError 404, 'Page not found.' 对于错误的页面请求。 当我发现我犯的错误

 require 'colors' console.error error.stack.red # logs where any error occured if error instanceof RequestError # proper response for user errors response.status(error.status).send(error.message) else response.status(500).send('Internal Server Error') # for 'other' errors the user only gets back a 500 'Internal Server Error'