Error Handling refers to how Express catches and processes errors that occur both synchronously and asynchronously. 错误处理是指Express如何捕获和处理同步和异步发生的错误。Express comes with a default error handler so you don’t need to write your own to get started.Express附带了一个默认的错误处理程序,因此您无需编写自己的错误处理程序即可开始。
It’s important to ensure that Express catches all errors that occur while running route handlers and middleware.确保Express捕获运行路由处理程序和中间件时发生的所有错误非常重要。
Errors that occur in synchronous code inside route handlers and middleware require no extra work. 路由处理程序和中间件内部的同步代码中发生的错误不需要额外的工作。If synchronous code throws an error, then Express will catch and process it. 若同步代码抛出错误,则Express将捕获并处理该错误。For example:例如:
app.get('/', function (req, res) {
throw new Error('BROKEN') // Express will catch this on its own.
})
For errors returned from asynchronous functions invoked by route handlers and middleware, you must pass them to the 对于路由处理程序和中间件调用的异步函数返回的错误,必须将它们传递给next()
function, where Express will catch and process them. next()
函数,Express将在其中捕获并处理它们。For example:例如:
app.get('/', function (req, res, next) {
fs.readFile('/file-does-not-exist', function (err, data) {
if (err) {
next(err) // Pass errors to Express.
} else {
res.send(data)
}
})
})
Starting with Express 5, route handlers and middleware that return a Promise will call 从Express 5开始,返回承诺的路由处理程序和中间件将在拒绝或抛出错误时自动调用next(value)
automatically when they reject or throw an error. next(value)
。For example:例如:
app.get('/user/:id', async function (req, res, next) {
var user = await getUserById(req.params.id)
res.send(user)
})
If 如果getUserById
throws an error or rejects, next
will be called with either the thrown error or the rejected value. getUserById
抛出错误或拒绝,则将使用抛出的错误或拒绝的值调用next。If no rejected value is provided, 如果未提供拒绝值,则将使用Express router提供的默认错误对象调用next
will be called with a default Error object provided by the Express router.next
。
If you pass anything to the 如果将任何内容传递给next()
function (except the string 'route'
), Express regards the current request as being an error and will skip any remaining non-error handling routing and middleware functions.next()
函数(字符串“route”除外),Express会将当前请求视为错误,并将跳过所有剩余的非错误处理路由和中间件函数。
If the callback in a sequence provides no data, only errors, you can simplify this code as follows:如果序列中的回调不提供数据,只提供错误,则可以按如下方式简化此代码:
app.get('/', [
function (req, res, next) {
fs.writeFile('/inaccessible-path', 'data', next)
},
function (req, res) {
res.send('OK')
}
])
In the above example 在上面的示例中,next
is provided as the callback for fs.writeFile
, which is called with or without errors. next
作为fs.writeFile
的回调提供,无论调用时有无错误。If there is no error the second handler is executed, otherwise Express catches and processes the error.如果没有错误,则执行第二个处理程序,否则Express将捕获并处理错误。
You must catch errors that occur in asynchronous code invoked by route handlers or middleware and pass them to Express for processing. 您必须捕获路由处理程序或中间件调用的异步代码中发生的错误,并将其传递给Express进行处理。For example:例如:
app.get('/', function (req, res, next) {
setTimeout(function () {
try {
throw new Error('BROKEN')
} catch (err) {
next(err)
}
}, 100)
})
The above example uses a 上面的示例使用try...catch
block to catch errors in the asynchronous code and pass them to Express. try...catch
块捕获异步代码中的错误并将其传递给Express。If the 如果省略了try...catch
block were omitted, Express would not catch the error since it is not part of the synchronous handler code.try...catch
块,Express将不会捕获错误,因为它不是同步处理程序代码的一部分。
Use promises to avoid the overhead of the 使用承诺可以避免try...catch
block or when using functions that return promises. try...catch
块的开销,或者在使用返回承诺的函数时。For example:例如:
app.get('/', function (req, res, next) {
Promise.resolve().then(function () {
throw new Error('BROKEN')
}).catch(next) // Errors will be passed to Express.
})
Since promises automatically catch both synchronous errors and rejected promises, you can simply provide 由于承诺会自动捕获同步错误和被拒绝的承诺,因此您可以简单地提供next
as the final catch handler and Express will catch errors, because the catch handler is given the error as the first argument.next
作为最终的捕获处理程序,Express将捕获错误,因为捕获处理程序将错误作为第一个参数。
You could also use a chain of handlers to rely on synchronous error catching, by reducing the asynchronous code to something trivial. 您还可以使用一系列处理程序来依赖同步错误捕获,方法是将异步代码简化为琐碎的代码。For example:例如:
app.get('/', [
function (req, res, next) {
fs.readFile('/maybe-valid-file', 'utf-8', function (err, data) {
res.locals.data = data
next(err)
})
},
function (req, res) {
res.locals.data = res.locals.data.split(',')[1]
res.send(res.locals.data)
}
])
The above example has a couple of trivial statements from the 上面的例子有几个来自readFile
call. readFile
调用的简单语句。If 如果readFile
causes an error, then it passes the error to Express, otherwise you quickly return to the world of synchronous error handling in the next handler in the chain. readFile
导致错误,那么它会将错误传递给Express,否则您将在链中的下一个处理程序中快速返回到同步错误处理的世界。Then, the example above tries to process the data. 然后,上面的示例尝试处理数据。If this fails then the synchronous error handler will catch it. 如果失败,那么同步错误处理程序将捕获它。If you had done this processing inside the 如果您在readFile
callback then the application might exit and the Express error handlers would not run.readFile
回调中完成了此处理,则应用程序可能会退出,而Express错误处理程序将不会运行。
Whichever method you use, if you want Express error handlers to be called in and the application to survive, you must ensure that Express receives the error.无论使用哪种方法,如果希望调用Express错误处理程序并使应用程序继续运行,则必须确保Express接收到错误。
Express comes with a built-in error handler that takes care of any errors that might be encountered in the app. Express附带一个内置的错误处理程序,用于处理应用程序中可能遇到的任何错误。This default error-handling middleware function is added at the end of the middleware function stack.此默认错误处理中间件函数添加在中间件函数堆栈的末尾。
If you pass an error to 如果将错误传递给next()
and you do not handle it in a custom error handler, it will be handled by the built-in error handler; the error will be written to the client with the stack trace. next()
,而不在自定义错误处理程序中处理,则将由内置错误处理程序处理;错误将与堆栈跟踪一起写入客户端。The stack trace is not included in the production environment.生产环境中不包括堆栈跟踪。
Set the environment variable 将环境变量NODE_ENV
to production
, to run the app in production mode.NODE_ENV
设置为production
,以在生产模式下运行应用程序。
When an error is written, the following information is added to the response:写入错误时,将向响应中添加以下信息:
res.statusCode
is set from err.status
(or err.statusCode
). res.statusCode
是根据err.status
(或err.statusCode
)设置的。res.statusMessage
is set according to the status code.res.statusMessage
根据状态代码设置。err.stack
.err.stack
。err.headers
object.err.headers
对象中指定的任何头。If you call 如果在开始编写响应后调用next()
with an error after you have started writing the response (for example, if you encounter an error while streaming the response to the client) the Express default error handler closes the connection and fails the request.next()
时出错(例如,如果将响应流式传输到客户端时遇到错误),则Express default error handler将关闭连接并使请求失败。
So when you add a custom error handler, you must delegate to the default Express error handler, when the headers have already been sent to the client:因此,当添加自定义错误处理程序时,必须在标头已发送到客户端时,将其委托给默认的Express错误处理程序:
function errorHandler (err, req, res, next) {
if (res.headersSent) {
return next(err)
}
res.status(500)
res.render('error', { error: err })
}
Note that the default error handler can get triggered if you call 请注意,如果在代码中多次调用next()
with an error in your code more than once, even if custom error handling middleware is in place.next()
,并且出现错误,则会触发默认错误处理程序,即使已安装自定义错误处理中间件。
Define error-handling middleware functions in the same way as other middleware functions, except error-handling functions have four arguments instead of three:以与其他中间件函数相同的方式定义错误处理中间件函数,但错误处理函数有四个参数,而不是三个:(err, req, res, next)
. For example:。例如:
app.use(function (err, req, res, next) {
console.error(err.stack)
res.status(500).send('Something broke!')
})
You define error-handling middleware last, after other 最后,在其他app.use()
and routes calls; for example:app.use()
和路由调用之后定义错误处理中间件;例如:
var bodyParser = require('body-parser')
var methodOverride = require('method-override')
app.use(bodyParser.urlencoded({
extended: true
}))
app.use(bodyParser.json())
app.use(methodOverride())
app.use(function (err, req, res, next) {
// logic
})
Responses from within a middleware function can be in any format, such as an HTML error page, a simple message, or a JSON string.中间件函数中的响应可以是任何格式,例如HTML错误页、简单消息或JSON字符串。
For organizational (and higher-level framework) purposes, you can define several error-handling middleware functions, much as you would with regular middleware functions. 出于组织(和更高级别的框架)的目的,您可以定义几个错误处理中间件功能,就像您使用常规中间件功能一样。For example, to define an error-handler for requests made by using 例如,要为使用XHR和不使用XHR
and those without:XHR
的请求定义错误处理程序,请执行以下操作:
var bodyParser = require('body-parser')
var methodOverride = require('method-override')
app.use(bodyParser.urlencoded({
extended: true
}))
app.use(bodyParser.json())
app.use(methodOverride())
app.use(logErrors)
app.use(clientErrorHandler)
app.use(errorHandler)
In this example, the generic 在本例中,通用logErrors
might write request and error information to stderr
, for example:logErrors
可能会将请求和错误信息写入stderr
,例如:
function logErrors (err, req, res, next) {
console.error(err.stack)
next(err)
}
Also in this example, 同样在本例中,clientErrorHandler
is defined as follows; in this case, the error is explicitly passed along to the next one.clientErrorHandler
的定义如下:;在这种情况下,错误会显式传递给下一个错误。
Notice that when not calling “next” in an error-handling function, you are responsible for writing (and ending) the response. 请注意,在错误处理函数中不调用“next”时,您负责编写(并结束)响应。Otherwise those requests will “hang” and will not be eligible for garbage collection.否则,这些请求将“挂起”,并且不符合垃圾收集的条件。
function clientErrorHandler (err, req, res, next) {
if (req.xhr) {
res.status(500).send({ error: 'Something failed!' })
} else {
next(err)
}
}
Implement the “catch-all” 实现“捕获所有”errorHandler
function as follows (for example):errorHandler
函数,如下所示(例如):
function errorHandler (err, req, res, next) {
res.status(500)
res.render('error', { error: err })
}
If you have a route handler with multiple callback functions you can use the 如果您有一个具有多个回调函数的路由处理程序,则可以使用route
parameter to skip to the next route handler. route
参数跳到下一个路由处理程序。For example:例如:
app.get('/a_route_behind_paywall',
function checkIfPaidSubscriber (req, res, next) {
if (!req.user.hasPaid) {
// continue handling this request
next('route')
} else {
next()
}
}, function getPaidContent (req, res, next) {
PaidContent.find(function (err, doc) {
if (err) return next(err)
res.json(doc)
})
})
In this example, the 在本例中,将跳过getPaidContent
handler will be skipped but any remaining handlers in app
for /a_route_behind_paywall
would continue to be executed.getPaidContent
处理程序,但将针对/a_route_behind_paywall
继续执行App
后面的所有剩余处理程序。
Calls to 调用next()
and next(err)
indicate that the current handler is complete and in what state. next()
和next(err)
表示当前处理程序已完成,并且处于什么状态。next(err)
will skip all remaining handlers in the chain except for those that are set up to handle errors as described above.next(err)
将跳过链中所有剩余的处理程序,但设置为如上所述处理错误的处理程序除外。