簡體   English   中英

nodejs API 服務器中錯誤處理的正確方法

[英]Propper way of Error handling in a nodejs API server

我需要處理 node.js 上的 API 服務器中的錯誤。 我創建了一個錯誤處理模塊,它將錯誤(僅在開發模式下)發送到 JSON object 中的 API 客戶端,類似於:

{
    "status": "fail",
    "error": {
        "statusCode": 404,
        "status": "fail",
        "isOperational": true
    },
    "message": "no valid register found. Please provide a valid register",
    "stack": "Error: no valid register found. Please provide a valid register\n    at /Users/myUser/ITstuff/smarthome-heating/controllers/modbusController.js:77:21\n    at async /Users/myUser/ITstuff/smarthome-heating/controllers/modbusController.js:73:17"
}

現在我遇到的問題是,當 switch 語句中沒有 case 為真時,我需要在我的 API controller 的子模塊中創建一個新錯誤。

// this is the modbusHandler.setValue(doc, val, next) function
// 2) RUN PROGRAMMS
  let checkVal;
  switch (doc.register) {
    case 0:
      await client.writeCoil(doc.address + offset, !!val);
      checkVal = await client.readCoils(doc.address + offset, 1);
      break;
    case 4:
      await client.writeRegister(doc.address + offset, val);
      checkVal = await client.readHoldingRegisters(doc.address + offset, 1);
      break;
    default:
      throw new Error(
    'no valid register found. Please provide a valid register'
  );
  }

這時候,我是這樣處理的:

// the function is wrapped in a try-catch statement
     const val = await modbusHandler.setValue(doc, req.body.value, next).catch((err) => {
                    console.log('here it is');
                    return next(new AppError(err.message, 404));
                  });


res.status(200).json({
    status: 'success',
    data: {
      val,
    },
  });
  1. 在 API controller 中,調用了帶有 switch 語句的 function
  2. 如果沒有大小寫與表達式匹配,則拋出一個新的錯誤
  3. 捕獲錯誤然后調用自定義錯誤並以 JSON 格式向客戶端響應錯誤

此解決方案實際上不起作用,我收到響應錯誤,因為 API controller 的 function 沒有返回。 這會導致第二個響應,這當然是不好的。

我現在的問題是:我怎樣才能以正確的方式解決這個問題?

自定義錯誤構造函數:

class AppError extends Error {
  constructor(message, statusCode) {
    // this is the official error message rom the error it self, this message will be in the response.json for the client
    super(message);

    this.statusCode = statusCode;
    this.status = `${statusCode}`.startsWith('4') ? 'fail' : 'error';
    this.isOperational = true;

    Error.captureStackTrace(this, this.constructor);
  }
}

module.exports = AppError;

自定義錯誤處理程序:

module.exports = (err, req, res, next) => {
  err.statusCode = err.statusCode || 500;
  err.status = err.status || 'error';

  if (process.env.NODE_ENV === 'development') {
    sendErrDev(err, res);
  } else if (process.env.NODE_ENV === 'production') {
    sendErrProd(err, res);
  }
};


const sendErrDev = (err, res) => {
  res.status(err.statusCode).json({
    status: err.status,
    error: err,
    message: err.message,
    stack: err.stack,
  });
};

而不是拋出錯誤,也許希望像這樣將它拋出到下一個,以便它可以由錯誤處理程序處理。

export const yourFunction = async (req, res, next) => {
   .....
   // throw the error to your route Error handler 
   return next(new AppError('no valid register found. Please provide a valid register', 400)) 
}

然后在所有路由聲明之后,您應該有一個看起來像的錯誤處理程序。

app.use(ErrorHandler);

您可能還需要一個錯誤捕獲器

//catchAsync
module.exports = fn => {
    return (req, res, next) => {
      fn(req, res, next).catch(next);
    };
  };

您將像這樣包裝您的路線。

route.get('/path/', catchAsync(yourFunction))

如果您創建了 catchAsync 中間件,則您的路由中根本不需要任何 Try/Catch,因為所有這些都將被扔給您的錯誤處理程序。

更新。

關於節點的小抱怨,甚至 javascript 都是關於錯誤處理的。 對於每個調用的 function 的 function 的 function 的 function ,那么你需要拋出錯誤的錯誤的錯誤。 你不斷冒泡“拋出錯誤”,然后它就會失控。

在您的 switch 語句中,我建議您返回 null。

然后你測試`if (;variable) return next(new AppError);

輔助函數的行為應該類似於輔助函數 function,它應該返回真/假/空/值,然后您在主 function 中確定是否應該拋出錯誤。

這樣你就可以集中你的錯誤。

暫無
暫無

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

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