Express 錯(cuò)誤處理

2024-12-03 18:00 更新

錯(cuò)誤處理

定義錯(cuò)誤處理中間件和定義其他中間件一樣,除了需要 4 個(gè)參數(shù),而不是 3 個(gè),其格式如下 (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)用后,最后定義錯(cuò)誤處理中間件,比如:

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)一個(gè) HTML 錯(cuò)誤頁(yè)面、一句簡(jiǎn)單的話、一個(gè) JSON 字符串,或者其他任何您想要的東西。

為了便于組織(更高級(jí)的框架),您可能會(huì)像定義常規(guī)中間件一樣,定義多個(gè)錯(cuò)誤處理中間件。比如您想為使用 XHR 的請(qǐng)求定義一個(gè),還想為沒(méi)有使用的定義一個(gè),那么:

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 將請(qǐng)求和錯(cuò)誤信息寫(xiě)入標(biāo)準(zhǔn)錯(cuò)誤輸出、日志或類似服務(wù):

function logErrors(err, req, res, next) {
  console.error(err.stack);
  next(err);
}

clientErrorHandler 的定義如下(注意這里將錯(cuò)誤直接傳給了 next):

function clientErrorHandler(err, req, res, next) {
  if (req.xhr) {
    res.status(500).send({ error: 'Something blew up!' });
  } else {
    next(err);
  }
}

errorHandler 能捕獲所有錯(cuò)誤,其定義如下:

function errorHandler(err, req, res, next) {
  res.status(500);
  res.render('error', { error: err });
}

如果向 next() 傳入?yún)?shù)(除了 ‘route’ 字符串),Express 會(huì)認(rèn)為當(dāng)前請(qǐng)求有錯(cuò)誤的輸出,因此跳過(guò)后續(xù)其他非錯(cuò)誤處理和路由/中間件函數(shù)。如果需做特殊處理,需要?jiǎng)?chuàng)建新的錯(cuò)誤處理路由,如下節(jié)所示。

如果路由句柄有多個(gè)回調(diào)函數(shù),可使用 ‘route’ 參數(shù)跳到下一個(gè)路由句柄。比如:

app.get('/a_route_behind_paywall', 
  function checkIfPaidSubscriber(req, res, next) {
    if(!req.user.hasPaid) { 
    
      // 繼續(xù)處理該請(qǐng)求
      next('route');
    }
  }, function getPaidContent(req, res, next) {
    PaidContent.find(function(err, doc) {
      if(err) return next(err);
      res.json(doc);
    });
  });

在這個(gè)例子中,句柄 getPaidContent 會(huì)被跳過(guò),但 app 中為 /a_route_behind_paywall 定義的其他句柄則會(huì)繼續(xù)執(zhí)行。

next()next(err) 類似于 Promise.resolve()Promise.reject()。它們讓您可以向 Express 發(fā)信號(hào),告訴它當(dāng)前句柄執(zhí)行結(jié)束并且處于什么狀態(tài)。next(err) 會(huì)跳過(guò)后續(xù)句柄,除了那些用來(lái)處理錯(cuò)誤的句柄。

缺省錯(cuò)誤處理句柄

Express 內(nèi)置了一個(gè)錯(cuò)誤處理句柄,它可以捕獲應(yīng)用中可能出現(xiàn)的任意錯(cuò)誤。這個(gè)缺省的錯(cuò)誤處理中間件將被添加到中間件堆棧的底部。

如果你向 next() 傳遞了一個(gè) error ,而你并沒(méi)有在錯(cuò)誤處理句柄中處理這個(gè) error,Express 內(nèi)置的缺省錯(cuò)誤處理句柄就是最后兜底的。最后錯(cuò)誤將被連同堆棧追蹤信息一同反饋到客戶端。堆棧追蹤信息并不會(huì)在生產(chǎn)環(huán)境中反饋到客戶端。

設(shè)置環(huán)境變量 NODE_ENV 為 “production” 就可以讓?xiě)?yīng)用運(yùn)行在生產(chǎn)環(huán)境模式下。

如果你已經(jīng)開(kāi)始向 response 輸出數(shù)據(jù)了,這時(shí)才調(diào)用 next() 并傳遞了一個(gè) error,比如你在將向客戶端輸出數(shù)據(jù)流時(shí)遇到一個(gè)錯(cuò)誤,Express 內(nèi)置的缺省錯(cuò)誤處理句柄將幫你關(guān)閉連接并告知 request 請(qǐng)求失敗。

因此,當(dāng)你添加了一個(gè)自定義的錯(cuò)誤處理句柄后,如果已經(jīng)向客戶端發(fā)送包頭信息了,你還可以將錯(cuò)誤處理交給 Express 內(nèi)置的錯(cuò)誤處理機(jī)制。

function errorHandler(err, req, res, next) {
  if (res.headersSent) {
    return next(err);
  }
  res.status(500);
  res.render('error', { error: err });
}
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)