定義錯誤處理中間件和定義其他中間件一樣,除了需要 4 個參數(shù),而不是 3 個,其格式如下 (err, req, res, next)
。例如:
app.use(function(err, req, res, next) {
console.error(err.stack);
res.status(500).send('Something broke!');
});
在其他 app.use()
和路由調(diào)用后,最后定義錯誤處理中間件,比如:
var bodyParser = require('body-parser');
var methodOverride = require('method-override');
app.use(bodyParser());
app.use(methodOverride());
app.use(function(err, req, res, next) {
// 業(yè)務(wù)邏輯
});
中間件返回的響應(yīng)是隨意的,可以響應(yīng)一個 HTML 錯誤頁面、一句簡單的話、一個 JSON 字符串,或者其他任何您想要的東西。
為了便于組織(更高級的框架),您可能會像定義常規(guī)中間件一樣,定義多個錯誤處理中間件。比如您想為使用 XHR 的請求定義一個,還想為沒有使用的定義一個,那么:
var bodyParser = require('body-parser');
var methodOverride = require('method-override');
app.use(bodyParser());
app.use(methodOverride());
app.use(logErrors);
app.use(clientErrorHandler);
app.use(errorHandler);
logErrors
將請求和錯誤信息寫入標準錯誤輸出、日志或類似服務(wù):
function logErrors(err, req, res, next) {
console.error(err.stack);
next(err);
}
clientErrorHandler
的定義如下(注意這里將錯誤直接傳給了 next
):
function clientErrorHandler(err, req, res, next) {
if (req.xhr) {
res.status(500).send({ error: 'Something blew up!' });
} else {
next(err);
}
}
errorHandler
能捕獲所有錯誤,其定義如下:
function errorHandler(err, req, res, next) {
res.status(500);
res.render('error', { error: err });
}
如果向 next()
傳入?yún)?shù)(除了 ‘route’ 字符串),Express 會認為當前請求有錯誤的輸出,因此跳過后續(xù)其他非錯誤處理和路由/中間件函數(shù)。如果需做特殊處理,需要創(chuàng)建新的錯誤處理路由,如下節(jié)所示。
如果路由句柄有多個回調(diào)函數(shù),可使用 ‘route’ 參數(shù)跳到下一個路由句柄。比如:
app.get('/a_route_behind_paywall',
function checkIfPaidSubscriber(req, res, next) {
if(!req.user.hasPaid) {
// 繼續(xù)處理該請求
next('route');
}
}, function getPaidContent(req, res, next) {
PaidContent.find(function(err, doc) {
if(err) return next(err);
res.json(doc);
});
});
在這個例子中,句柄 getPaidContent
會被跳過,但 app
中為 /a_route_behind_paywall
定義的其他句柄則會繼續(xù)執(zhí)行。
next()
和 next(err)
類似于 Promise.resolve()
和 Promise.reject()
。它們讓您可以向 Express 發(fā)信號,告訴它當前句柄執(zhí)行結(jié)束并且處于什么狀態(tài)。next(err)
會跳過后續(xù)句柄,除了那些用來處理錯誤的句柄。
Express 內(nèi)置了一個錯誤處理句柄,它可以捕獲應(yīng)用中可能出現(xiàn)的任意錯誤。這個缺省的錯誤處理中間件將被添加到中間件堆棧的底部。
如果你向 next()
傳遞了一個 error ,而你并沒有在錯誤處理句柄中處理這個 error,Express 內(nèi)置的缺省錯誤處理句柄就是最后兜底的。最后錯誤將被連同堆棧追蹤信息一同反饋到客戶端。堆棧追蹤信息并不會在生產(chǎn)環(huán)境中反饋到客戶端。
設(shè)置環(huán)境變量 NODE_ENV
為 “production” 就可以讓應(yīng)用運行在生產(chǎn)環(huán)境模式下。
如果你已經(jīng)開始向 response 輸出數(shù)據(jù)了,這時才調(diào)用 next()
并傳遞了一個 error,比如你在將向客戶端輸出數(shù)據(jù)流時遇到一個錯誤,Express 內(nèi)置的缺省錯誤處理句柄將幫你關(guān)閉連接并告知 request 請求失敗。
因此,當你添加了一個自定義的錯誤處理句柄后,如果已經(jīng)向客戶端發(fā)送包頭信息了,你還可以將錯誤處理交給 Express 內(nèi)置的錯誤處理機制。
function errorHandler(err, req, res, next) {
if (res.headersSent) {
return next(err);
}
res.status(500);
res.render('error', { error: err });
}
更多建議: