Error Handling错误处理
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附带了一个默认的错误处理程序,因此您不需要自己编写错误处理程序即可开始。
Catching Errors捕捉错误
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. For example:路由处理程序和中间件中同步代码中发生的错误不需要额外的工作。如果同步代码抛出错误,Express将捕获并处理它。例如:
app.get('/', (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. For example:next()
函数,Express将在其中捕获并处理它们。例如:
app.get('/', (req, res, next) => {
fs.readFile('/file-does-not-exist', (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(值)。next(value)
automatically when they reject or throw an error.
For example:例如:
app.get('/user/:id', async (req, res, next) => {
const 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路由器提供的默认Error对象调用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. For example:您必须捕获路由处理程序或中间件调用的异步代码中出现的错误,并将其传递给Express进行处理。例如:
app.get('/', (req, res, next) => {
setTimeout(() => {
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 使用promises来避免try...catch
block or when using functions
that return promises. For example:try...catch
块的开销或使用返回promise的函数时。例如:
app.get('/', (req, res, next) => {
Promise.resolve().then(() => {
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 由于promise会自动捕获同步错误和被拒绝的promise,因此您可以简单地提供next
as the final catch handler and Express will catch errors,
because the catch handler is given the error as the first argument.next
作为最终的catch
处理程序,Express将捕获错误,因为catch
处理程序将错误作为第一个参数。
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', (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收到错误。
The default error handler默认错误处理程序
Express comes with a built-in error handler that takes care of any errors that might be encountered in the app. This default error-handling middleware function is added at the end of the middleware function stack.Express附带了一个内置的错误处理程序,可以处理应用程序中可能遇到的任何错误。此默认错误处理中间件功能添加在中间件功能堆栈的末尾。
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:当写入错误时,以下信息将添加到响应中:
Theres.statusCode
is set fromerr.status
(orerr.statusCode
). If this value is outside the 4xx or 5xx range, it will be set to 500.res.statusCode
代码是从err.status
(或err.statusCode
)设置的。如果此值在4xx或5xx范围之外,则将设置为500。The根据状态代码设置res.statusMessage
is set according to the status code.res.statusMessage
。The body will be the HTML of the status code message when in production environment, otherwise will be在生产环境中,正文将是状态代码消息的HTML,否则将是err.stack
.err.stack
。Any headers specified in anerr.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默认错误处理程序将关闭连接并使请求失败。
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()
,即使有自定义错误处理中间件,默认错误处理程序也可能被触发。
Other error handling middleware can be found at Express middleware.其他错误处理中间件可以在Express中间件中找到。
Writing error handlers编写错误处理程序
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:(err, req, res, next)
。例如:
app.use((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()
和路由调用之后,最后定义错误处理中间件;例如:
const bodyParser = require('body-parser')
const methodOverride = require('method-override')
app.use(bodyParser.urlencoded({
extended: true
}))
app.use(bodyParser.json())
app.use(methodOverride())
app.use((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
and those without:XHR
发出的请求和不使用XHR
的请求定义错误句柄:
const bodyParser = require('body-parser')
const 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. Otherwise, those requests will “hang” and will not be eligible for garbage collection.请注意,在错误处理函数中不调用“next”时,您有责任编写(并结束)响应。否则,这些请求将“挂起”,并且没有资格进行垃圾回收。
function clientErrorHandler (err, req, res, next) {
if (req.xhr) {
res.status(500).send({ error: 'Something failed!' })
} else {
next(err)
}
}
Implement the “catch-all” 按如下方式实现“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. For example:route
参数跳到下一个路由处理程序。例如:
app.get('/a_route_behind_paywall',
(req, res, next) => {
if (!req.user.hasPaid) {
// continue handling this request
next('route')
} else {
next()
}
}, (req, res, next) => {
PaidContent.find((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
处理程序将被跳过,但app
中/a_route_behind_paywall
的任何剩余处理程序都将继续执行。
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)
将跳过链中所有剩余的处理程序,但如上所述设置为处理错误的处理程序除外。