[Spring] 서블릿 예외 처리

JJoSuk·2023년 6월 12일
0

본 프로젝트 자료는 김영한님의 스프링 MVC 2편 - 백엔드 웹 개발 활용 기술을 참고 제작됐음을 알립니다.

스프링 예외 처리를 배우기 전 서블릿은 예외 처리를 어떻게 하는지 배워볼려고 한다.

기본적으로 서블릿은 2가지 예외 처리 기능을 제공한다.

  • Exception
  • response.sendError(HTTP 상태 코드, 오류 메시지)

1. Exception(예외)

자바 직접 실행

자바의 메인 메서드를 직접 실행하는 경우 main 이라는 이름의 쓰레드가 실행된다.
실행 도중에 예외를 잡지 못하고 처음 실행한 main() 메서드를 넘어서 예외가 던져지면, 예외 정보를 남기고 해당 쓰레드는 종료된다.

웹 애플리케이션

웹 애플리케이션은 사용자 요청별로 별도의 쓰레드가 할당되고, 서블릿 컨테이너 안에서 실행된다. 애플리케이션에서 예외가 발생했는데, 어디선가 try ~ catch로 예외를 잡아서 처리하면 아무런 문제가 없다.

애플리케이션 부터 서블릿 밖까지 예외를 잡지 못하면 순서대로 전달되는 방식이 있는데,

순서대로 예외를 처리 못하고 WAS까지 예외가 전달된다면 어떻게 처리하는지 테스트 해볼려고 한다.

그럼 애플리케이션에서 처리 못하고 부트가 제공하는 기본 예외 페이지를 꺼야한다.

application.properties - 추가

ServletExController - 신규 클래스 생성

서블릿 예외 컨트롤러 추가

실행 시켜서 예외 발생을 순서대로 출력해본다.

  • Exception 은 내부에서 처리할 수 없을 때 500으로 표시해준다.

2. response.sendError(HTTP 상태 코드, 오류 메시지)

  • HttpServletResponse 가 제공하는 sendError 라는 메서드를 사용해도 된다.
  • 서블릿 컨테이너에게 오류가 발생했다는 점을 전달한다.
  • 이 메서드를 사용하면 HTTP 상태 코드와 오류 메시지도 추가할 수 있다.
    • response.sendError(HTTP 상태 코드)
    • response.sendError(HTTP 상태 코드, 오류 메시지)

ServletExController - 신규 클래스 생성

서블릿 예외 컨트롤러 추가

  • response.sendError() 를 호출하면 response 내부에는 오류가 발생했다는 상태를 저장한다.
  • 서블릿 컨테이너는 사용자가 호출 전, response 에 sendError() 가 호출되었는지 확인.
    • 호출이 된다면, 설정한 오류 코드에 맞춰 페이지에 오류 페이지를 출력한다.

서블릿 예외 처리 - 오류 화면 제공

서블릿 컨테이너가 제공하는 기본 예외 처리 화면은 실제 사용자에게 보여주기에 친화적이지 않다.

서블릿은 Exception (예외)가 발생해서 서블릿 밖으로 전달되거나 또는 response.sendError() 가 호출 되었을 때 각각의 상황에 맞춘 오류 처리 기능을 제공한다.

이 기능을 사용하면 친절한 오류 처리 화면을 준비해서 고객에게 보여줄 수 있다.

WebServerCustomizer 신규 클래스 생성

서블릿 오류 페이지 등록

각 404, 500 에러 생길 때 호출해주는 로직 생성

ErrorPageController 신규 클래스 생성

해당 오류를 해결해줄 컨트롤러 역할

오류 처리 View 생성

404 오류 화면

500 오류 화면

실행 결과

설정한 페이지들이 정상적으로 호출되는지 확인


서블릿 예외 처리 - 오류 페이지 작동 원리

예외 발생 흐름

sendError 흐름

WAS 까지 오류가 전달된다면 WAS는 다시 한번 해당 예외를 처리하는 오류 페이지 정보를 확인한다.

오류 페이지 요청 흐름

예외 발생과 오류 페이지 요청 흐름

  • 웹 브라우저(클라이언트)는 서버 내부에서 이런 일이 일어나는지 전혀 모른다.
  • 오직 서버 내부에서 오류 페이지를 찾기 위해 추가적인 호출을 한다.

정리

  • 예외가 발생해서 WAS까지 전파된다.
  • WAS는 오류 페이지 경로를 찾아서 내부에서 오류 페이지를 호출한다.
  • 이때 오류 페이지 경로로 필터, 서블릿, 인터셉터, 컨트롤러가 모두 다시 호출된다.

오류 정보 추가

WAS는 오류 페이지를 단순히 다시 요청만 하는 것이 아니라, 오류 정보를 request 의 attribute 에 추가해서 넘겨준다.

ErrorPageController - 수정

어떤 오류가 터졌는지 육안으로 확인하기 위해 오류 출력하기.

이대로 실행시켜본다.

출력 결과

오류 404가 떳다는 가정으로 404를 출력해보면 위와 같이 에러 정보들이 출력된다.


서블릿 예외 처리 - 필터

예외 처리에 따른 필터와 인터셉터 그리고 서블릿이 제공하는 DispatchType 가 뭔지 확인해보자.

예외 발생과 오류 페이지 요청 흐름

  • 오류가 발생하면 WAS 는 다시 한번 더 호출한다.(필터, 서블릿, 인터셉터도 모두 다시 호출)
  • 하지만 이런 방식은 한번 더 호출되는건 어떤 상황에서는 비효율적 일 수 있다.
  • 그래서 클라이언트로 부터 발생한 정상 호출인지, 오류 페이지 출력하기 위한 내부 호출인지 구분해야 한다.
  • DispatcherType 가 위와 같은 추가 정보를 제공해 준다.

DispatcherType

서블릿 스펙은 서버가 내부에서 오류 페이지를 요청하는 것인지 DispatcherType 으로 구분할 수 있는 방법을 제공한다.

예시

이제 필터와 DispatcherType 가 어떻게 사용되는 알아볼려고 한다.

LogFilter - 추가

필터와 DispatcherType

WebConfig - 추가

이렇게만 하고 출력해서 결과를 확인해본다.

출력 결과

두 번 호출되는 것을 확인할 수 있다.


서블릿 예외 처리 - 인터셉터

서블릿 예외 처리할 때 인터셉터를 통해 중복처리를 막아보자.

LogInterceptor - DispatcherType 로그 추가

앞서 필터의 경우에는 필터를 등록할 때 어떤 DispatcherType 인 경우에 필터를 적용할 지 선택할 수 있었다. 그런데 인터셉터는 서블릿이 제공하는 기능이 아니라 스프링이 제공하는 기능이다. 따라서 DispatcherType 과 무관하게 항상 호출된다.

대신에 인터셉터는 다음과 같이 요청 경로에 따라서 추가하거나 제외하기 쉽게 되어 있기 때문에, 이러한 설정을 사용해서 오류 페이지 경로를 excludePathPatterns 를 사용해서 빼주면 된다.

WebConfig - 수정

중복 처리 방지를 위해 기존 빈은 주석 처리했다.

전체 흐름 정리

정상 요청일 경우

오류 요청일 경우

  • 필터는 DispatchType 으로 중복 호출 제거 ( dispatchType=REQUEST )
  • 인터셉터는 경로 정보로 중복 호출 제거( excludePathPatterns("/error-page/**") )

profile
안녕하세요

0개의 댓글