Error Handling(https://www.expressjs.com.cn/guide/error-handling.html)
本文的【錯(cuò)誤處理】指Express如何捕獲和處理(同步和異步的)錯(cuò)誤。Express有一個(gè)默認(rèn)的錯(cuò)誤處理handler捣卤,所以一開始不是必須寫自己的錯(cuò)誤處理handler爱只。
捕獲錯(cuò)誤
Catching Errors
保證Express會(huì)捕獲運(yùn)行路由handlers和中間件時(shí)發(fā)生的所有錯(cuò)誤非常重要蝙砌。
在路由handlers和中間件的同步代碼中發(fā)生的錯(cuò)誤不需要做額外的工作(Errors that occur in synchronous code inside route handlers and middleware require no extra work),Express會(huì)捕獲和處理适肠。
但路由handlers和中間件中調(diào)用的異步函數(shù)拋出的錯(cuò)誤耿币,我們就需要將異常捕獲,使用next()函數(shù) 將錯(cuò)誤傳入(next(error))容贝, 使Express能夠捕獲和處理這個(gè)錯(cuò)誤。
tips:next函數(shù)除了傳入字符串'route'之景,其他參數(shù)都會(huì)被認(rèn)為是錯(cuò)誤嗤疯,會(huì)跳過余下所有非錯(cuò)誤處理的路由和中間件函數(shù)
//
app.get('/', [
function(req, res, next) {
fs.writeFile('/file-does-not-exit', data, function(err, data){
if(err) {
next(err);
} else {
res.send(data);
}
});
}
])
// 直接將next作為callback函數(shù),
//有錯(cuò)誤時(shí)next有參數(shù) 攜帶錯(cuò)誤參數(shù)被Express error handler捕獲并處理闺兢,
// 無錯(cuò)誤時(shí) next無參數(shù) , 執(zhí)行下一個(gè)handler
app.get('/', [
function(req, res, next) {
fs.writeFile('/file-does-not-exit', data, function(err, data){
if(err) {
next(err);
} else {
res.send(data);
}
});
}
])
// 需捕獲異常
app.get('/', function (req, res, next) {
setTimeout(function () {
try {
throw new Error('BROKEN')
} catch (err) {
next(err)
}
}, 100)
})
// 使用promise 代替 try catch
app.get('/', function (req, res, next) {
Promise.resolve().then(function(){
throw new Error('BROKEN')
}).catch(next)
})
默認(rèn)的錯(cuò)誤處理函數(shù)
The default error handler
沒有自定義錯(cuò)誤處理函數(shù),用next(error)傳入錯(cuò)誤的時(shí)候戏罢,express默認(rèn)的錯(cuò)誤處理函數(shù)進(jìn)行處理屋谭,會(huì)同時(shí)輸出調(diào)用棧信息(NODE_ENV的值為production時(shí)不會(huì)打印調(diào)用棧信息)
需要注意的一點(diǎn)是,如果已經(jīng)開始寫response龟糕,調(diào)用了next(error), Express的默認(rèn)錯(cuò)誤處理函數(shù)會(huì)關(guān)閉連接桐磁,此次請(qǐng)求會(huì)失敗。
所以在自定義的error handler中讲岁,當(dāng)header已經(jīng)被發(fā)送給client端我擂,發(fā)生錯(cuò)誤的話需要將錯(cuò)誤傳給默認(rèn)的錯(cuò)誤處理函數(shù)(???)
如果你在你的代碼調(diào)用next()出現(xiàn)錯(cuò)誤多次,則會(huì)觸發(fā)默認(rèn)錯(cuò)誤處理程序缓艳,即使自定義錯(cuò)誤處理中間件已就緒也是如此(???)
function errorHandler (err, req, res, next) {
if (res.headersSent) {
return next(err)
}
res.status(500)
res.render('error', { error: err })
}
如何實(shí)現(xiàn)錯(cuò)誤處理函數(shù)
Writing error handlers
定義錯(cuò)誤處理中間件函數(shù)的方式與定義其他中間件函數(shù)一樣校摩,只是錯(cuò)誤處理中間件的參數(shù)是4個(gè) err, req,res ,next
我們需要在最后定義錯(cuò)誤處理中間件函數(shù),在其他的app.use 和路由調(diào)用之后阶淘。
中間件函數(shù)的返回值可以是任意格式衙吩,如html錯(cuò)誤頁面,簡(jiǎn)單的字符串信息 或json字符串
如果在error handler中沒有調(diào)用next函數(shù)溪窒,則需要負(fù)責(zé)返回響應(yīng)坤塞,否則請(qǐng)求會(huì)被掛起冯勉,并且不會(huì)被垃圾回收機(jī)制回收