StrongLoop 提供的 Express 和 Node.js 訓練課程

這個翻譯StrongLoop / IBM提供.

相對於英文版說明文件,本文件可能已不合時宜。如需最新的更新,請參閱英文版說明文件

錯誤處理

錯誤處理中介軟體函數的定義方式,與其他中介軟體函數相同,差別在於錯誤處理函數的引數是四個而非三個:(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) {
  // logic
});

中介軟體函數內的回應可以是任何您喜好的格式,如: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 可能將要求和錯誤資訊寫入至 stderr,例如:


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

此外在本例中,clientErrorHandler 定義成如下;在此情況下,會將錯誤明確傳遞給下一個:


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

“catch-all” 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) {

      // continue handling this request
      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),指出現行處理程式已完成以及處於何種狀態。除了依上述說明設定成用來處理錯誤的那些處理程式,next(err) 會跳過處理程式鏈中其餘所有的處理程式。</div>

預設錯誤處理程式

Express 隨附一個內建錯誤處理常式,它會處理應用程式中可能遇到的任何錯誤。這個預設錯誤處理中介軟體函數新增於中介軟體函數堆疊尾端。

如果您傳遞錯誤至 next(),且您沒有在錯誤處理常式中處理它,將會交由內建錯誤處理常式處理;該錯誤會連同堆疊追蹤寫入至用戶端。在正式作業環境中,則不包含堆疊追蹤。

NODE_ENV 環境變數設為 production,以便在正式作業模式下執行應用程式。

在您開始撰寫回應之後,一旦在呼叫 next() 時才發生錯誤(例如,當您將回應串流輸出至用戶端時遇到錯誤),Express 的預設錯誤處理程式會關閉連線,並使要求失敗。

因此,在您新增自訂錯誤處理常式時,如果標頭已傳送給用戶端,您會希望委派給 Express 中的預設錯誤處理機制處理:


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