如何处理 node.js 中的代码异常?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10390658/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to handle code exceptions in node.js?
提问by user124114
I went through the documentation of Express, and the part describing error handlingis completely opaque to me.
我浏览了 Express 的文档,描述错误处理的部分对我来说完全不透明。
I figured the appthey're referring to is an instance createServer(), right? But I have no clue how to stop node.js from blowing up the application process when an exception occurs during handling a request.
我想app他们所指的是一个实例createServer(),对吧?但是我不知道如何在处理请求期间发生异常时阻止 node.js 炸毁应用程序进程。
I don't need anything fancy really; I just want to return a status of 500, plus an otherwise empty response, whenever there's an exception. The node process must notterminate just because there was an uncaught exception somewhere.
我真的不需要任何花哨的东西;每当出现异常时,我只想返回 500 的状态,再加上一个空响应。节点进程不能仅仅因为某处存在未捕获的异常而终止。
Is there a simple example of how to achieve this?
有没有一个简单的例子来说明如何实现这一目标?
var express = require('express');
var http = require('http');
var app = express.createServer();
app.get('/', function(req, res){
console.log("debug", "calling")
var options = {
host: 'www.google.com',
port: 80,
path: "/"
};
http.get(options, function(response) {
response.on("data", function(chunk) {
console.log("data: " + chunk);
chunk.call(); // no such method; throws here
});
}).on('error', function(e) {
console.log("error connecting" + e.message);
});
});
app.configure(function(){
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.listen(3000);
crashes the entire app, producing traceback
使整个应用程序崩溃,产生回溯
mypath/tst.js:16
chunk.call(); // no such method; throws here
^ TypeError: Object ... has no method 'call'
at IncomingMessage.<anonymous> (/Library/WebServer/Documents/discovery/tst.js:16:18)
at IncomingMessage.emit (events.js:67:17)
at HTTPParser.onBody (http.js:115:23)
at Socket.ondata (http.js:1150:24)
at TCP.onread (net.js:374:27)
回答by metamatt
If you really want to catch all exceptions and provide some handling other than exiting the Node.js process, you need to handle Node's uncaughtExceptionevent.
如果你真的想捕获所有异常并提供一些除了退出 Node.js 进程之外的处理,你需要处理 Node 的uncaughtException事件。
If you think about it, this is a Node thing, and not an Express thing, because if you throw an exception from some arbitrary piece of code, there's no guarantee Express can or will ever see it, or be in a position to trap it. (Why? Exceptions don't interact very well with asynchronous event-driven callbacky code that is the Node style. Exceptions travel up the call stack to find a catch()block that's in scope at the time the exception is thrown. If myFunctiondefers some work to a callback function that runs when some event happens, then return to the event loop, then when that callback function is invoked, it's invoked directly from the main event loop, and myFunctionis no longer on the call stack; if this callback function throws an exception, even if myFunctionhas a try/catch block, it's not going to catch the exception.)
如果你考虑一下,这是一个 Node 的东西,而不是一个 Express 的东西,因为如果你从任意一段代码中抛出一个异常,就不能保证 Express 可以或永远看到它,或者能够捕获它. (为什么?异常不能与 Node 风格的异步事件驱动回调代码很好地交互。异常沿着调用堆栈向上移动以查找catch()在抛出异常时在范围内的块。如果myFunction将某些工作推迟到当某个事件发生时运行的回调函数,然后返回到事件循环,然后当该回调函数被调用时,它会直接从主事件循环中调用,并且myFunction不再在调用堆栈中;如果该回调函数抛出异常,即使myFunction有一个 try/catch 块,它不会捕获异常。)
What this means in practice is that if you throw an exception and don't catch it yourself and you do so in a function that was directly called by Express, Express can catch the exception and call the error handler you've installed, assuming you've configured some piece of error-handling middleware like app.use(express.errorHandler()). But if you throw the same exception in a function that was called in response to an asynchronous event, Express won't be able to catch it. (The only way it could catch it is by listening for the global Node uncaughtExceptionevent, which would be a bad idea first because that's global and you might need to use it for other things, and second because Express will have no idea what request was associated with the exception.)
这在实践中意味着如果你抛出一个异常并且没有自己捕获它并且你在一个由 Express 直接调用的函数中这样做,Express 可以捕获异常并调用你安装的错误处理程序,假设你已经配置了一些错误处理中间件,例如app.use(express.errorHandler()). 但是,如果在响应异步事件而调用的函数中抛出相同的异常,Express 将无法捕获它。(它可以捕获它的唯一方法是侦听全局 NodeuncaughtException事件,这首先是一个坏主意,因为它是全局的,您可能需要将它用于其他事情,其次是因为 Express 不知道关联了什么请求有这个特例。)
Here's an example. I add this snippet of route-handling code to an existing Express app:
这是一个例子。我将这段路由处理代码添加到现有的 Express 应用程序中:
app.get('/fail/sync', function(req, res) {
throw new Error('whoops');
});
app.get('/fail/async', function(req, res) {
process.nextTick(function() {
throw new Error('whoops');
});
});
Now if I visit http://localhost:3000/fail/syncin my browser, the browser dumps a call stack (showing express.errorHandler in action). If I visit http://localhost:3000/fail/asyncin my browser, however, the browser gets angry (Chrome shows a "No data received: Error 324, net::ERR_EMPTY_RESPONSE: The server closed the connection without sending any data" message), because the Node process has exited, showing a backtrace on stdout in the terminal where I invoked it.
现在,如果我http://localhost:3000/fail/sync在浏览器中访问,浏览器会转储调用堆栈(显示 express.errorHandler 正在运行)。http://localhost:3000/fail/async但是,如果我在浏览器中访问,浏览器会生气(Chrome 显示“未收到数据:错误 324,net::ERR_EMPTY_RESPONSE:服务器关闭连接而未发送任何数据”消息),因为 Node 进程已退出,在我调用它的终端中显示 stdout 上的回溯。
回答by Johnny Tsang
To be able to catch asynchronous errors I use domain. With Express you can try this code:
为了能够捕获异步错误,我使用了域。使用 Express,您可以尝试以下代码:
function domainWrapper() {
return function (req, res, next) {
var reqDomain = domain.create();
reqDomain.add(req);
reqDomain.add(res);
res.on('close', function () {
reqDomain.dispose();
});
reqDomain.on('error', function (err) {
next(err);
});
reqDomain.run(next)
}
}
app.use(domainWrapper());
//all your other app.use
app.use(express.errorHandler());
This code will make your asynchronous error be captured and sent to your error handler. In this example I use the express.errorHandler, but it works with any handler.
此代码将使您的异步错误被捕获并发送到您的错误处理程序。在本例中,我使用 express.errorHandler,但它适用于任何处理程序。
For more information about domain: http://nodejs.org/api/domain.html
有关域的更多信息:http: //nodejs.org/api/domain.html
回答by 250R
You can use the default error handler that express uses, which is actually connect error handler.
您可以使用 express 使用的默认错误处理程序,它实际上是连接错误处理程序。
var app = require('express').createServer();
app.get('/', function(req, res){
throw new Error('Error thrown here!');
});
app.configure(function(){
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.listen(3000);
UpdateFor your code, you actually need to capture the error and pass it to express like this
更新对于您的代码,您实际上需要捕获错误并将其传递给这样的表达
var express = require('express');
var http = require('http');
var app = express.createServer();
app.get('/', function (req, res, next) {
console.log("debug", "calling");
var options = {
host:'www.google.com',
port:80,
path:"/"
};
http.get(options,
function (response) {
response.on("data", function (chunk) {
try {
console.log("data: " + chunk);
chunk.call(); // no such method; throws here
}
catch (err) {
return next(err);
}
});
}).on('error', function (e) {
console.log("error connecting" + e.message);
});
});
app.configure(function () {
app.use(express.errorHandler({ dumpExceptions:true, showStack:true }));
});
app.listen(3000);
回答by phil294
express 5.0.0-alpha.7 came out 27 days ago. With this very specific pre-release version, you can now finally reject a promise inside a request handler and it will be handled properly:
express 5.0.0-alpha.7 27 天前出来了。使用这个非常具体的预发布版本,您现在可以最终拒绝请求处理程序中的承诺,它将被正确处理:
Middleware and handlers can now return promises and if the promise is rejected, next(err) will be called with err being the value of the rejection. (source)
中间件和处理程序现在可以返回承诺,如果承诺被拒绝,next(err) 将被调用,err 是拒绝的值。(来源)
For example:
例如:
app.get('/', async () => {
throw new Error();
});
app.use((err, req, res, next) => {
res.status(500).send('unexpected error :(');
});
However, only use this as a fallback. Proper error handling should still happen inside catch-phrases inside the request handlers themselves with proper error status codes.
但是,仅将其用作后备。正确的错误处理应该仍然发生在请求处理程序内部的标语中,并带有正确的错误状态代码。

