스프링이 아닌 서블릿 컨테이너는 예외를 어떻게 처리하는가?
서블릿은 다음 2가지 방식으로 예외 처리를 지원한다.
1. Exception
웹 애플리케이션에서 try ~ catch
구문으로 예외를 처리하게 된다면 문제가 없다. 그러나 예외를 잡지 못하고, 톰캣과 같은 WAS까지 예외가 전달됐을 경우에 어떻게 처리할지 살펴보자.
* WAS(여기까지 전파) <- 필터 <- 서블릿 <- 인터셉터 <- 컨트롤러(예외발생)
Exception
의 경우, 내부에서 처리할 수 없는 오류로 인지하여 HTTP 상태 코드 500을 반환
2. response.sendError()
HttpServletResponse
가 제공하는 sendError()
메서드를 통해 서블릿 컨테이너에게 오류 발생을 알릴 수 있다. 해당 메서드를 통해 HTTP 상태 코드와 오류 메시지를 추가할 수 있다.
* WAS(오류 상태 확인) <- 필터 <- 서블릿 <- 인터셉터 <- 컨트롤러(response.sendError())
response.sendError()
를 통해 response
내부에는 오류가 발생했다는 상태를 저장하고, 서블릿 컨테이너는 응답 전, response
에 오류 상태를 확인하여 그에 맞는 오류 페이지를 호출
서블릿 컨테이너가 제공하는 기본 예외 처리 화면은 사용자가 보기 불편하다는 단점을 지니고 있다
WebServerCustomizer
생성ErrorPage
생성 스프링 부트가 제공하는 기능을 통해 고객 친화적인 서블릿 오류 페이지를 등록 !
위 과정을 거쳐 오류 페이지를 등록하였을 때, 오류 페이지 요청 흐름은 다음과 같다.
1. WAS(여기까지 전파) <- 필터 <- 서블릿 <- 인터셉터 <- 컨트롤러(예외발생)
2. WAS `/오류 페이지` 요청 -> 필터 -> 서블릿 -> 인터셉터 -> 컨트롤러(`/오류 페이지`) -> View
오류가 발생하면 내부에서 다시 호출이 발생하는 것을 확인할 수 있다. 이 때, 필터, 서블릿, 인터셉터까지 다시 호출되면서 비효율적인 과정을 가지게 된다.
이러한 문제를 해결하기 위해 서블릿은 DispatcherType
을 제공한다.
이러한 옵션을 제공함으로 실제 고객이 요청한 것인지, 서버 내부에서 오류 페이지를 요청하는 것인지 구분할 수 있다.
public enum DispatcherType {
FORWARD, // 서블릿에서 다른 서블릿 혹은 JSP 호출할 때
INCLUDE, // 서블릿에서 다른 서블릿이나 JSP의 결과를 포함할 때
REQUEST, // 클라이언트 요청
ASYNC, // 서블릿 비동기 요청
ERROR // 오류 요청
}
필터에 다음과 같은 메서드를 추가함으로, 오류 요청일 경우에 필터를 호출하지 않는다.
filterBean.setDispatcherTypes(DispatcherType.REQUEST);
해당 메서드의 기본값이 DispatcherType.REQUEST
이다. 오류 페이지 경로도 필터를 적용하지 않는다면 기본 값 그대로 사용하면 된다.
오류 페이지 경로도 필터를 적용하고 싶다면
DispatcherType.ERROR
추가하자.
이전 글에서도 확인할 수 있듯이 인터셉터는 스프링이 제공하는 기능으로 DispatcherType
과 무관하게 항상 호출된다.
대신에 인터셉터는 경로의 추가/제거가 자유롭기에 excludePathPatterns
을 통해 설정할 수 있다.
registry.excludePathPatterns("....", "...." , "/오류 페이지 경로")
스프링은 위와 같은 복잡한 과정없이 다음을 기본으로 제공한다.
/error
라는 경로로 기본 오류 페이지를 설정한다. BasicErrorController
라는 스프링 컨트롤러를 자동으로 등록한다.BasicErrorController
BasicErrorController
는 기본적인 로직이 모두 개발되어 있어 개발자는 우선순위에 따라 화면을 등록하면 된다.
뷰 템플릿
resources/templates/error/500.html
resources/templates/error/5xx.html
정적 리소스
resources/static/error/404.html
resources/static/error/4xx.html
적용 대상이 없을 때 뷰 이름(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
포함 여부
never
외 always
, on_param
옵션도 사용 가능하지만 앞서 말했듯이 보안상의 문제가 생길 수 있어 디버그 시 문제를 확인하는 용도로 개발 서버에서만 on_param
옵션을 사용하는 것을 권장한다.
server.error.whitelabel.enabled=true
: 스프링 WhiteLabel 오류 페이지 적용
📌 본 포스트는 스프링 MVC 2편 - 백엔드 웹 개발 핵심 기술 통해 학습한 내용을 요약 및 정리한 것입니다.