[NodeJS] express 에러 핸들링

seonjeong·2023년 6월 20일

NodeJS

목록 보기
12/19
post-thumbnail

💖 오류 처리 미들웨어

express로 에러를 알리기 위해서는 에러를 던지거나 next()를 사용해야 한다.
그러나 전자에서는 비동기로 에러를 던질 경우 에러를 잡지 못한다.
오류 처리 미들웨어는 맨 아래에 위치해야 한다.

🔥 throw new Error

const app = require("express")()

app.get("*", function (req, res, next) {
  // 이 미들웨어가 에러를 던지면 익스프레스는 곧바로 다음 오류 처리기로 이동
  throw new Error("에러 발생");
})

app.get("*", function (req, res, next) {
  // 이전 미들웨어에서 에러가 발생했기 때문에 스킵됨
  console.log("this will not print");
})

// 오류 처리 미들웨어(4개의 인자)
app.use(function (error, req, res, next) {
  // 이 서버로 들어온 모든 요청은 여기에 올 것이고
  // 에러 메세지 '에러 발생'와 함께 HTTP 응답을 보낼 것
  res.json({ message: error.message });
})

app.listen(3000)

  • 비동기로 에러를 던질 경우
const app = require("express")()

app.get("*", function (req, res, next) {
  setImmediate(() => {
    throw new Error("woops")
  })
})

app.use(function (error, req, res, next) {
  // 위 에러를 잡지 못한다
  res.json({ message: error.message })
})

app.listen(3000)

🔥 next()

const app = require("express")()

app.get("*", function (req, res, next) {
  setImmediate(() => {
    next(new Error("woops"))
  })
})

app.use(function (error, req, res, next) {
  // error가 도달할 수 있다
  res.json({ message: error.message })
})

app.listen(3000)

💖 Async/Await

  • async가 붙은 함수는 Promise객체를 반환한다.
  • 다음은 Async/Await구문에서의 에러 핸들링이다.(타입스크립트로 작성됨)

🔥 Promise객체의 catch 메소드 이용

import { Request, Response, NextFunction } from "express";

type AsyncRequestHandler = (
  req: Request,
  res: Response,
  next: NextFunction
) => Promise<any>;

export const wrapAsync = (fn: AsyncRequestHandler) => {
  return (req: Request, res: Response, next: NextFunction) => {
    // 모든 오류를 .catch() 처리 후 next() 미들웨어에 전달
    fn(req, res, next).catch(next);
  };
};

🔥 try-catch 구문

import { Request, Response, NextFunction } from "express";

type AsyncRequestHandler = (
  req: Request,
  res: Response,
  next: NextFunction
) => Promise<any>;

export const wrapAsync = (fn: AsyncRequestHandler) => {
    return async (req: Request, res: Response, next: NextFunction) => {
    try {
      await fn(req, res, next);
    } catch (error) {
      next(error);
    }
  };
};

💖 에러 로직 분리

🔥 CustomError

export class CustomError extends Error {
  statusCode: number;

  constructor(message: string, statusCode: number) {
    super(message);
    this.statusCode = statusCode;
  }
}

🔥 BadRequest

import { HttpCode } from "./HttpCode";
import { CustomError } from "./CustomError";

export class BadRequest extends CustomError {
  constructor(message: string) {
    // HttpCode는 열거형(enum) 데이터, BAD_REQUEST:400
    super(message, HttpCode.BAD_REQUEST);
  }
}

🔥 InternalServerError

import { HttpCode } from "./HttpCode";
import { CustomError } from "./CustomError";

export class InternalServerError extends CustomError {
  constructor(message: string) {
    super(message, HttpCode.INTERNAL_SERVER_ERROR);	// 500
  }
}

🔥 ErrorHandler 미들웨어

import { Request, Response, NextFunction } from "express";
import { CustomError } from "../errors/CustomError";
import { BadRequest } from "../errors/BadRequest";
import { InternalServerError } from "../errors/InternalServerError";

export const errorHandler = (
  error: Error,
  req: Request,
  res: Response,
  next: NextFunction
) => {
  console.error("에러 발생:", error);

  if (
    error instanceof CustomError ||
    error instanceof BadRequest ||
    error instanceof InternalServerError	// 예상치 못한 서버 오류
  ) {
    res.status(error.statusCode).json({ error: error.message });
  } else {
    // 일반적인 서버 오류
    res.status(500).json({ error: "서버 에러 발생" });
  }
};




Reference

https://jeonghwan-kim.github.io/node/2017/08/17/express-error-handling.html
https://velog.io/@tmpks5/express-%EC%97%90%EB%9F%AC-%ED%95%B8%EB%93%A4%EB%A7%81-%EB%A1%9C%EC%A7%81-%EB%B6%84%EB%A6%AC-%EB%B0%8F-Custom-Error-%EC%A0%9C%EC%9E%91

profile
🦋개발 공부 기록🦋

0개의 댓글