[내배캠] TIL, WIL/TIL

노드JS 익스프레스 서버 에러 핸들링

값싼외노자 2023. 1. 9. 10:05

에러가 발생할 경우 에러 예외 처리를 해두지 않으면 서버가 다운되는 상황이 있을 수 있다.

 

그렇기에 에러 핸들링은 필수적으로 해야한다.

 

노드JS의 경우 우리가 늘 사용해왔던 것처럼 app.use()를 통해 미들웨어를 사용할 수 있는데 이를 이용하여 에러만 따로 처리하는 미들웨어도 쉽게 사용이 가능하다.

 

 

1. Error handling 미들웨어 선언하기

기본적으로 익스프레스에서 오류를 처리하는 공통 미들웨어는 아래와 같이 작성한다.

app.use(function (err, req, res, next) {
  console.error(err.stack);
  res.status(500).send("알 수 없는 에러가 발생하였습니다. 관리자에게 문의해 주세요.");
});

인자 3개를 선언하면 일반적인 미들웨어고 에러 미들웨어는 인자 4개를 선언한다.

 

 

익스프레스-제너레이터로 만들어보면 아래와 같다.

// catch 404 and forward to error handler
app.use(function (req, res, next) {
  next(createError(404));
});

// error handler
app.use(function (err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get("env") === "development" ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render("error");
});

주의할 점은 익스프레스-제너레이터로 만들경우 // 에러 핸들링의 코드는 맨 아래에 배치해야한다.

 

2. Async Await 사용

익스프레스는 ES6이 나오기 이전에 거의 다 만들어졌기에 비동기 에러를 처리하는데 잘 작동하지 않는다.

프로미스 리젝트 시 에러 처리 미들웨어에서 사용이 되지 않는 것을 볼 수 있다.

app.get("*", function (req, res) {
  return new Promise((resolve, reject) => {
    setImmediate(() => reject(new Error("에러 발생")));
  });
});

app.use(function (error, req, res, next) {
  console.log("호출 되지 않음!");
  res.json({ message: error.message });
});
(node:6852) UnhandledPromiseRejectionWarning: Error: 에러 발생
    at Immediate.<anonymous> (/Users/gim-yohan/Desktop/Projects/nodejs/mysessionApp/app.js:34:20)
    at processImmediate (internal/timers.js:456:21)
(node:6852) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)

 

 

3. 헬퍼 함수 사용하기 비동기 오류 처리하기

function wrapAsync(fn) {
  return function (req, res, next) {
    // 모든 오류를 .catch() 처리하고 next()로 전달하기
    fn(req, res, next).catch(next);
  };
}

헬퍼 함수로 wrapAsync를 커스텀으로 만들면 된다. 한줄로 쓸 수도 있다.

const wrapAsync = (fn) => (req, res, next) => fn(req, res, next).catch(next);
app.get(
  "*",
  wrapAsync(async function (req, res) {
    await new Promise((resolve) => setTimeout(() => resolve(), 50));
    // 비동기 에러
    throw new Error("에러 발생!");
  })
);

app.use(function (error, req, res, next) {
  res.json({ message: error.message });
});

app.listen(3000);

function wrapAsync(fn) {
  return function (req, res, next) {
    // 모든 오류를 .catch() 처리하고 체인의 next() 미들웨어에 전달
    // (이 경우에는 오류 처리기)
    fn(req, res, next).catch(next);
  };
}

 

'[내배캠] TIL, WIL > TIL' 카테고리의 다른 글

Typescript - 유니온/교차 타입  (0) 2023.01.29
TypeScript  (0) 2023.01.17
TIL  (0) 2023.01.09
TIL  (0) 2023.01.03
TIL  (0) 2022.12.31