当我第一次开始使用Express并试图弄清楚如何处理错误时,我很难受。 感觉没有人写我需要的东西。 结果,我不得不自己寻找问题的答案。 今天,我想告诉我有关Express应用程序中错误处理的所有知识。 让我们从同步错误开始。

同步错误处理
如果需要处理同步错误,则可以首先使用
throw
语句在Express请求处理程序中
throw
此类错误。 请注意,请求处理程序也称为“控制器”,但我更喜欢使用“请求处理程序”一词,因为在我看来,这更清楚。
看起来是这样的:
app.post('/testing', (req, res) => { throw new Error('Something broke! ') })
可以使用Express错误处理程序捕获此类错误。 如果您尚未编写自己的错误处理程序(我们将在下文中详细讨论),则Express将使用默认处理程序来处理错误。
这是标准Express错误处理程序的作用:
- 将HTTP响应状态代码设置为500。
- 向执行请求的实体发送文本响应。
- 将文本响应记录到控制台。
控制台中显示错误消息异步错误处理
要处理异步错误,您需要通过
next
参数将错误发送到Express错误处理程序:
app.post('/testing', async (req, res, next) => { return next(new Error('Something broke again! ')) })
这是记录此错误时进入控制台的内容。
控制台中显示错误消息如果在Express应用程序中使用async / await构造,则需要使用包装函数,例如
express-async-handler 。 这使您可以编写异步代码而无需
try / catch块。 在
此处阅读有关Express中异步/等待的更多信息。
const asyncHandler = require('express-async-handler') app.post('/testing', asyncHandler(async (req, res, next) => {
将请求处理程序包装在
express-async-handler
,您可以如上所述使用
throw
语句引发错误。 该错误将转到Express错误处理程序。
app.post('/testing', asyncHandler(async (req, res, next) => { throw new Error('Something broke yet again! ') }))
控制台中显示错误消息编写自己的错误处理程序
Express错误处理程序采用4个参数:
- 错误
- 要求
- 资源
- 下一个
您需要将它们放置在中间处理程序和路由之后。
app.use() app.get() app.post() app.put() app.delete()
如果您创建自己的错误处理程序,Express将停止使用标准错误处理程序。 为了处理错误,您需要为前端应用程序生成一个响应,该响应对发生错误的端点进行了寻址。 这意味着您需要执行以下操作:
- 生成并发送适当的响应状态代码。
- 形成并发送适当的答案。
在每种情况下哪种状态代码合适,取决于发生了什么。 这是您应该准备处理的常见错误列表:
- 错误
400 Bad Request
。 在两种情况下使用。 首先,当用户未在请求中包括必填字段时(例如,带有信用卡信息的字段未填写在发送的付款表单中)。 其次,当请求包含不正确的数据时(例如,在密码字段和密码确认字段中输入不同的密码)。 - 错误
401 Unauthorized
。 如果用户输入了错误的凭据(例如用户名,电子邮件地址或密码),则将应用此响应状态代码。 - 错误
403 Forbidden
。 在不允许用户访问端点时使用。 - 错误
404 Not Found
。 在无法检测到端点的情况下使用它。 - 错误
500 Internal Server Error
。 当前端发送的请求正确构成,但后端发生一些错误时,将应用此方法。
定义适当的响应状态代码后,必须使用
res.status
进行设置:
app.use((error, req, res, next) => {
响应状态代码应对应于错误消息。 为此,将状态代码与错误一起发送。
最简单的方法是使用
http-errors包。 它允许错误地发送三段信息:
- 响应状态码。
- 与错误关联的消息。
- 需要发送的任何数据(这是可选的)。
以下是安装
http-errors
软件包的方法:
npm install http-errors --save
这是使用此软件包的方法:
const createError = require('http-errors')
考虑一个示例,它将使您正确地理解所有这一切。
想象一下,我们正在尝试在其电子邮件地址中找到用户。 但是找不到该用户。 因此,我们决定响应相应的请求,发送“
User not found
错误,通知调用者未找到该用户。
这是创建错误时我们需要做的:
- 将响应状态代码设置为
400 Bad Request
(毕竟,用户输入了错误的数据)。 这将是我们的第一个参数。 - 将消息发送给呼叫者,例如“
User not found
。 这将是第二个参数。
app.put('/testing', asyncHandler(async (req, res) => { const { email } = req.body const user = await User.findOne({ email })
您可以使用
error.status
构造获取状态代码,并使用
error.message
获取错误消息:
控制台中记录错误的结果然后使用
res.status
设置响应状态,并将消息写入
res.json
:
app.use((error, req, res, next) => {
就我个人而言,我更喜欢在此类响应中发送状态代码,消息和堆栈跟踪结果。 这使调试更加容易。
app.use((error, req, res, next) => {
▍默认响应状态码
如果错误的来源不是
createError
,则它将没有
status
属性。 这是一个尝试使用
fs.readFile
读取不存在的文件的
fs.readFile
:
const fs = require('fs') const util = require('util')
这样的错误对象将不具有
status
属性:
app.use((error, req, res, next) => { console.log('Error status: ', error.status) console.log('Message: ', error.message) })
控制台中记录错误的结果在这种情况下,您可以设置默认错误代码。 即,我们正在谈论
500 Internal Server Error
:
app.use((error, req, res, next) => { res.status(error.status || 500) res.json({ status: error.status, message: error.message, stack: error.stack }) })
▍更改错误状态代码
假设我们将使用用户提供的数据读取某个文件。 如果这样的文件不存在,则意味着我们需要给出一个
400 Bad Request
错误。 毕竟,找不到服务器,因为找不到文件。
在这种情况下,您需要使用try / catch构造来捕获原始错误。 然后,您需要使用
createError
重新创建错误对象:
app.get('/testing', asyncHandler(async (req, res, next) => { try { const { file } = req.body const contents = await readFilePromise(path.join(__dirname, file)) } catch (error) { throw createError(400, `File ${file} does not exist`) } })
▍404错误处理
如果该请求经过所有中间处理程序和路由,但未处理,则意味着找不到与该请求相对应的端点。
要处理
404 Not Found
错误,您需要在路由和错误处理程序之间添加一个附加处理程序。 404错误对象的创建如下所示:
错误详情▍ERR_HTTP_HEADERS_SENT错误说明
如果看到错误消息
ERR_HTTP_HEADERS_SENT: Cannot set headers after they are sent to the client
请不要惊慌
ERR_HTTP_HEADERS_SENT: Cannot set headers after they are sent to the client
。 之所以会出现这种情况,是因为在同一处理程序中反复调用了设置响应头的方法。 以下是调用这些方法以自动设置响应头的方法:
- 重新发送
- res.json
- 重新渲染
- res.sendFile
- res.sendStatus
- 结束
- 重定向
因此,例如,如果在同一响应处理程序中调用
res.render
和
res.json
,则会收到错误
ERR_HTTP_HEADERS_SENT
:
app.get('/testing', (req, res) => { res.render('new-page') res.json({ message: '¯\_(ツ)_/¯' }) })
因此,如果遇到此错误,请仔细检查响应处理程序代码,并确保在任何情况下都不会调用上述几种方法。
▍错误处理和数据流
如果将响应流传输到前端时出了点问题,那么您可能会遇到相同的错误
ERR_HTTP_HEADERS_SENT
。
在这种情况下,必须将错误处理传递给标准处理程序。 这样的处理程序将发送错误并自动关闭连接。
app.use((error, req, res, next) => {
总结
今天,我告诉您有关Express中错误处理的所有知识。 我希望这可以帮助您编写更可靠的Express应用程序。
亲爱的读者们! 您如何处理Node.js项目中的错误?
