簡體   English   中英

ExpressJS 錯誤處理不起作用

[英]ExpressJS error handling doesn't work

在我的 server.js 文件的最后,我有以下代碼:

app.use(logErrors);

function logErrors (err: Error, req: Request, res: Response, next: NextFunction) {
    console.log(err);
    mongoDal.log(err.message, err);
    next(err);
}

但是發生錯誤時不會到達此代碼。

我也有 Node.js 錯誤處理功能,也沒有達到:

process.on('uncaughtException', function (err: Error) {
    try {
        console.log(err);
        mongoDal.log(err.message, err);
    } catch (err) {

    }
});

這是產生錯誤的代碼:

app.get('/test_feature', function (req: Request, res: Response) {
    makeError();

    res.send("Done");
});

function makeError(){
    throw new Error("asdasdad");
}

順便說一句,錯誤確實寫入了控制台(但不是我的功能),並且應用程序不會崩潰。

我正在嘗試制作一個通用解決方案,它將在一個地方捕獲每個未處理的異常。

我做錯了什么?

下面是處理 3 種類型錯誤的簡短工作示例:1) 傳遞給next()處理程序,2) 在路由處理程序內部拋出,3) 從路由處理程序調用的某些函數的回調中未處理的錯誤。

(1) 和 (2) 使用自定義錯誤中間件處理程序 (A) 捕獲,(3) 由uncaughtException處理程序 (B) uncaughtException

Express 有自己的錯誤處理程序,如果它使用next()調用鏈獲得控制權,則輸出錯誤(即,如果沒有自定義錯誤處理程序,或者如果它使用next(err, req, res, next)進一步傳遞控制權)。 這就是為什么即使您的處理程序不是觸發器,您仍然在控制台中收到錯誤消息的原因。

如果您嘗試針對情況 (1) 和 (2) 運行示例,您將看到兩次錯誤輸出 - 通過自定義處理程序 (A) 和默認 Express 錯誤處理程序。

'use strict';

var express = require('express');
var app = express();    

var server = app.listen(8080, function() {
  console.log('* Server listening at ' + server.address().address + ':' + server.address().port);
});

// Example 1: Pass error in route handler to next() handler
app.use('/1', function(req, res, next) {
  console.log('* route 1');
  next(new Error('* route 1 error'));
});

// Example 2: throw the error in route handler
app.use('/2', function(req, res, next) {
  console.log('* route 2');
  throw new Error('route 2 error');
});

// Example 3: unhandled error inside some callback function
app.use('/3', function(req, res, next) {
  console.log('* route 3');
  setTimeout(function(){
    throw new Error('route 3 error');
  }, 500);
});

// Error handler A: Express Error middleware
app.use(function(err, req, res, next) {
  console.log('**************************');
  console.log('* [Error middleware]: err:', err);
  console.log('**************************');
  next(err);
});

// Error handler B: Node's uncaughtException handler
process.on('uncaughtException', function (err) {
  console.log('**************************');
  console.log('* [process.on(uncaughtException)]: err:', err);
  console.log('**************************');
});

節點版本: v7.2.0

典型的錯誤是將錯誤處理程序放在路由定義之前,但根據您的描述,情況並非如此。

要定位問題,您可以嘗試將自己的代碼減少到與我相同的大小,我認為,問題會變得很明顯。


更新

此外,如果我嘗試運行您提供的代碼(稍作修改),它對我有用:

'use strict';

var express = require('express');
var app = express();

var server = app.listen(8080, function() {
  console.log('* Server listening at ' + server.address().address + ':' + server.address().port);
});

//process.on('uncaughtException', function (err: Error) {
process.on('uncaughtException', function (err) {
  try {
    console.log('*** uncaughtException:', err);
    //mongoDal.log(err.message, err);
  } catch (err) {

  }
});

//app.get('/test_feature', function (req: Request, res: Response) {
app.get('/test_feature', function (req, res) {
  makeError();
  res.send("Done");
});

function makeError(){
  throw new Error("asdasdad");
}

app.use(logErrors);

//function logErrors (err: Error, req: Request, res: Response, next: NextFunction) {
function logErrors (err, req, res, next) {
  console.log('*** logErrors:', err);
  //mongoDal.log(err.message, err);
  next(err);
}

結果是(堆棧跟蹤被截斷):

* Server listening at :::8080
*** logErrors: Error: asdasdad
    at makeError (/home/alykoshin/sync/al-projects/dev/nmotw/400-express-error-handling/main-stackoverflow.js:32:9)
...........
Error: asdasdad
    at makeError (/home/alykoshin/sync/al-projects/dev/nmotw/400-express-error-handling/main-stackoverflow.js:32:9)
...........

您可能會在開頭看到logErrors處理程序的輸出,然后是默認 Express 錯誤處理程序的輸出。

注意:您的錯誤處理程序中間件必須有 4 個參數:error、req、res、next。 否則你的處理程序不會觸發。

我一直在解決這個問題,直到我發現了這一點。

我認為問題出在路由定義上

正如你所說,你正在使用這個

app.get('/test_feature', function (req, res) {
    throw new Error("asdasdad");
    res.send("Done");
});

嘗試使用這個:

app.get('/test_feature', function (req, res, next) {
    next(new Error("asdasdad"));
});

然后將 res.send 放在錯誤處理程序上...

為什么?

我認為在函數內拋出一個錯誤會停止請求鏈......所以它不會到達最后,然后是你的錯誤處理程序。 如果你用第二種方式寫......你將錯誤向前移動......然后到達你的處理程序......

如果你想讓全局uncaughtException運行,你需要在沒有人捕捉到的地方拋出一個錯誤,像這樣:

app.get('/test_feature', function (req: Request, res: Response) {
    setTimeout(function () { throw new Error('oops'); }, 1000);

    res.send("Done");
});

處理程序中的同步throw被 express uncaughtException ,當它uncaughtException時根本沒有發生uncaughtException

根據http://expressjs.com/en/guide/error-handling.html您的路由和其他中間件之后定義了一個錯誤處理中間件。

app.get('/test_feature', function (req: Request, res: Response) {
    makeError();

    res.send("Done");
});

app.use(logErrors)

如果您得到錯誤的順序,則在拋出某些內容時將不會調用錯誤處理程序。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM