스프링 MVC 2편 - 예외 처리

hyuk·2024년 3월 4일
0
post-thumbnail

📌 서블릿의 예외 처리

스프링이 아닌 서블릿 컨테이너는 예외를 어떻게 처리하는가?

서블릿은 다음 2가지 방식으로 예외 처리를 지원한다.


1. Exception

웹 애플리케이션에서 try ~ catch 구문으로 예외를 처리하게 된다면 문제가 없다. 그러나 예외를 잡지 못하고, 톰캣과 같은 WAS까지 예외가 전달됐을 경우에 어떻게 처리할지 살펴보자.

* WAS(여기까지 전파) <- 필터 <- 서블릿 <- 인터셉터 <- 컨트롤러(예외발생) 

Exception의 경우, 내부에서 처리할 수 없는 오류로 인지하여 HTTP 상태 코드 500을 반환


2. response.sendError()

HttpServletResponse가 제공하는 sendError() 메서드를 통해 서블릿 컨테이너에게 오류 발생을 알릴 수 있다. 해당 메서드를 통해 HTTP 상태 코드와 오류 메시지를 추가할 수 있다.

* WAS(오류 상태 확인) <- 필터 <- 서블릿 <- 인터셉터 <- 컨트롤러(response.sendError()) 

response.sendError()를 통해 response 내부에는 오류가 발생했다는 상태를 저장하고, 서블릿 컨테이너는 응답 전, response에 오류 상태를 확인하여 그에 맞는 오류 페이지를 호출


서블릿 오류 페이지 등록

서블릿 컨테이너가 제공하는 기본 예외 처리 화면은 사용자가 보기 불편하다는 단점을 지니고 있다

  1. WebServerCustomizer 생성
  1. 예외 종류에 따른 ErrorPage 생성
  1. 예외 처리 컨트롤러 생성

스프링 부트가 제공하는 기능을 통해 고객 친화적인 서블릿 오류 페이지를 등록 !


오류 페이지 흐름

위 과정을 거쳐 오류 페이지를 등록하였을 때, 오류 페이지 요청 흐름은 다음과 같다.

1. WAS(여기까지 전파) <- 필터 <- 서블릿 <- 인터셉터 <- 컨트롤러(예외발생)

2. WAS `/오류 페이지`  요청 -> 필터 -> 서블릿 -> 인터셉터 -> 컨트롤러(`/오류 페이지`) -> View

오류가 발생하면 내부에서 다시 호출이 발생하는 것을 확인할 수 있다. 이 때, 필터, 서블릿, 인터셉터까지 다시 호출되면서 비효율적인 과정을 가지게 된다.

이러한 문제를 해결하기 위해 서블릿은 DispatcherType을 제공한다.

1) 필터 호출 X

이러한 옵션을 제공함으로 실제 고객이 요청한 것인지, 서버 내부에서 오류 페이지를 요청하는 것인지 구분할 수 있다.

public enum DispatcherType {
  FORWARD, 	// 서블릿에서 다른 서블릿 혹은 JSP 호출할 때
  INCLUDE,	// 서블릿에서 다른 서블릿이나 JSP의 결과를 포함할 때
  REQUEST,	// 클라이언트 요청
  ASYNC,	// 서블릿 비동기 요청
  ERROR		// 오류 요청
}

필터에 다음과 같은 메서드를 추가함으로, 오류 요청일 경우에 필터를 호출하지 않는다.

  • filterBean.setDispatcherTypes(DispatcherType.REQUEST);

해당 메서드의 기본값이 DispatcherType.REQUEST이다. 오류 페이지 경로도 필터를 적용하지 않는다면 기본 값 그대로 사용하면 된다.

오류 페이지 경로도 필터를 적용하고 싶다면 DispatcherType.ERROR 추가하자.

2) 인터셉터 호출 X

이전 글에서도 확인할 수 있듯이 인터셉터는 스프링이 제공하는 기능으로 DispatcherType과 무관하게 항상 호출된다.

대신에 인터셉터는 경로의 추가/제거가 자유롭기에 excludePathPatterns을 통해 설정할 수 있다.

  • registry.excludePathPatterns("....", "...." , "/오류 페이지 경로")

📌 스프링 부트 - 오류 페이지

스프링은 위와 같은 복잡한 과정없이 다음을 기본으로 제공한다.

  • /error 라는 경로로 기본 오류 페이지를 설정한다.
  • BasicErrorController 라는 스프링 컨트롤러를 자동으로 등록한다.

BasicErrorController

BasicErrorController는 기본적인 로직이 모두 개발되어 있어 개발자는 우선순위에 따라 화면을 등록하면 된다.

  1. 뷰 템플릿

    • resources/templates/error/500.html
    • resources/templates/error/5xx.html
  2. 정적 리소스

    • resources/static/error/404.html
    • resources/static/error/4xx.html
  3. 적용 대상이 없을 때 뷰 이름(error)

    • resources/templates/error.html

404, 500처럼 구체적인 것이 5xx, 4xx보다 우선순위 높음 !

주의사항

오류 관련 내부 정보들은 사용자에게 노출하지 않는 것이 좋다. 사용자의 혼란을 야기할 뿐만 아니라 보안상의 문제가 될 수 있기 때문이다.

  • server.error.include-exception=false : exception 포함 여부( true , false )

  • server.error.include-message=never : message 포함 여부

  • server.error.include-stacktrace=never : trace 포함 여부

  • server.error.include-binding-errors=never : errors 포함 여부

neveralways, on_param 옵션도 사용 가능하지만 앞서 말했듯이 보안상의 문제가 생길 수 있어 디버그 시 문제를 확인하는 용도로 개발 서버에서만 on_param 옵션을 사용하는 것을 권장한다.

server.error.whitelabel.enabled=true : 스프링 WhiteLabel 오류 페이지 적용


📌 본 포스트는 스프링 MVC 2편 - 백엔드 웹 개발 핵심 기술 통해 학습한 내용을 요약 및 정리한 것입니다.

profile
차곡차곡쌓아가는학습노트

0개의 댓글