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