Express에서 미들웨어를 활용한 에러처리하기

byeoung·2024년 9월 5일

미들웨어란?

요청과 응답 중간에 존재하여 미들웨어라 부른다.
미들웨어는 요청과 응답을 조작하여 기능을 추가하기도 하고, 잘못된 요청을 걸러내는 역할도 한다.

Express에서는 웹 요청과 응답에 대한 정보를 사용해서 필요한 처리를 진행할 수 있도록 분리된 독립적인 함수이다.

미들웨어 종류

1. 어플리케이션 레벨 미들웨어

app.use(미들웨어 함수) 또는 app.METHOD(미들웨어 함수)
( METHOD: get, post, delete ... )
내에서 정의되는 미들웨어를 의미한다.

2. 라우터 레벨 미들웨어

Express의 Router 객체에 bind된 미들웨어를 의미한다.

const router = express.Router();

router.get('/',(req, res) => { ... });

app.use('/api', router);

/api로 들어오는 요청에 대해서 등록된 미들웨어 함수가 동작한다.

3. 빌트인 미들웨어

Express에 내장된 미들웨어 함수를 의미한다.

4. 서드파티 미들웨어

서드파티 라이브러리에서 제공하는 미들웨어를 사용하여 기능을 추가할 수 있다.

5. 에러 핸들링 미들웨어

에러가 발생했을 때 호출되는 미들웨어이다.
일반미들웨어는 3개의 인자를 기본적으로 받지만 에러 핸들링 미들웨어는 4개의 인자를 받는다.

app.use((err, res, req, next) => {
  ...
}) 

에러 핸들링 미들웨어가 호출되는 경우

  • 동기 처리 시 발생한 에러
    동기 처리 시 발생한 에러는 try - catch문에서 throw Error를 할 경우 Express가 해당 에러를 잡아 에러 핸들링 미들웨어를 호출시킨다.
    하지만 더 일반적인 방법은 next(err)를 통해서 에러 핸들링 미들웨어를 호출해주는 것이 더 명시적이기 때문에 next(err) 표현을 활용하는 것이 더 좋다.
  • 비동기 처리 시 발생한 에러
    비동기 처리 시 발생한 에러는 동기 처리 시 발생한 에러와는 다르게 throw Error를 통해 발생한 에러를 Express가 잡아주지 못한다.
    그래서 이때는 명시적으로 next(err)를 통해서 에러 핸들링 미들웨어를 호출해주어야 한다.

미들웨어 추가 방법

1. 전역 미들웨어

모든 요청에 대해서 실행되는 미들웨어이다.

app.use(미들웨어 함수)를 활용하여 전역 미들웨어를 추가할 수 있다.
서버에 요청이 들어오면 항상 미들웨어 함수가 실행된다.

2. 특정 경로에 대한 미들웨어

특정 경로로 들어온 요청에 대해서만 미들웨어가 실행되도록 한다.

app.use('/api' , (req, res) => { ... })

app.use()의 첫번째 인자로 경로를 지정하여 특정 경로에 대해서만 미들웨어가 실행되도록 할 수 있다.

3. 여러 개의 미들웨어 등록

미들웨어 함수는 하나만이 아니라 여러개 등록할 수 있다.

app.use( (req, res) => { ...1... } , (req, res) => { ...2... })

단, 이때 순차적으로 미들웨어 함수가 실행되게 하기위해서는 next() 함수를 반드시 호출해야 한다.
위의 경우 ...1... 만 실행되고 다음 미들웨어 함수는 실행되지 않는다.

app.use( (res, res, next) => { ...1... next() } ,
        (req, res) => { ...2... })

위의 경우 처럼 앞선 미들웨어 함수에서 next()를 호출해야 다음 미들웨어 함수가 실행이 된다.

미들웨어 함수

  • 기본 인자 : req , res , next , err (에러 핸들링 미들웨어)

  • 인자의 역할 :
    req : request 객체 , 요청에 대한 정보를 담고 있다.
    res : response 객체 , 이를 통해 서버에서 클라이언트로 데이터를 전송하거나, 상태 코드를 설정하고, 응답 본문을 정의할 수 있다.
    next : 미들웨어 흐름 제어 , next(err) 시 에러 핸들링 미들웨어로 넘어간다.
    err : 에러 핸들링 미들웨어에서 사용되며 에러에 대한 정보를 담고 있다.

  • 2개 이상 미들웨어 함수를 등록할 수 있다.

Express에서 에러 핸들링 하기!

현재 BE 구조

현재 문제점

  1. 반복된 try-catch 사용

    service, controller의 모든 함수에서 try-catch문을 사용하고 있다.

  2. 구체화되지 않은 Error code

    대부분의 에러들이 500 에러로 구체화되어 있지 않다.

  3. Error handle Middleware의 미사용

    Error handle Middleware가 구현이 되어있으나 이를 활용하지 않고 있다.

문제 해결 방법

  1. 반복된 try-catch문 => Wrapper 함수 활용

    각 service, controller 함수들을 감싸는 wrapper함수를 만들어 두고 wrapper 함수 내에서 try-catch 문을 통해 에러 핸들링을 수행하였다.

    반복되어 사용하던 try-catch문을 줄일 수 있었다.

  2. 구체화되지 않은 Error code => custom Error class 선언 및 활용

    Error 클래스를 extends 하는 커스텀 에러 클래스를 선언해두고 예상되는 에러 사항에 맞는 에러 클래스들을 호출하여 에러를 세분화하여 관리하였다.

  3. Error handle Middleware 활용

    Controller 함수들을 감싸는 Wrapper함수에서 에러 발생 시 next(error)를 통해 에러 핸들링 미들웨어로 에러를 보내도록 하여 해당 미들웨어에서 에러 처리를 하도록 수행하였다.

[참고자료]:
[EXPRESS] 📚 미들웨어 이론 & 실용 💯 정리

0개의 댓글