서블릿 예외 처리
스프링이 아닌 순수 서블릿 컨테이너는 다음 2가지 방식으로 예외 처리를 지원한다.
- Exception(예외 던지기)
- response.sendError(HTTP 상태 코드, 오류 메시지)
Exception(예외)
자바 직접 실행 : 자바의 main( ) 메서드를 넘어 예외가 던져지면, 예외 정보를 남기고 해당 쓰레드는 종료
웹 애플리케이션
: 요청별로 별도의 쓰레드가 할당되고, 실행
: 예외가 발생했는데 예외를 잡지 못하면, WAS 까지 예외가 전달
: 컨트롤러(예외 발생) > 인터셉터 > 서블릿 > 필터 > WAS(여기까지 전파)
: 스프링 부트가 제공하는 기본 예외 페이지 (WhiteLable 화면)
: server.error.whitelabel.enabled=false
으로 옵션 끄면 tomcat 이 제공하는 기본 예외 페이지
response.sendError(HTTP 상태 코드, 오류 메시지)
HttpServletResponse 가 제공하는 sendError 메서드는 response 내부에 오류가 발생했다는 상태를 저장한다.
그리고 서블릿 컨테이너는 고객에게 응답하기 전 response 에 sendError( ) 가 호출되었는지 확인하고,
설정한 오류 코드에 맞는 예외 페이지를 보여준다.
response.sendError(HTTP 상태 코드)
response.sendError(HTTP 상태 코드, 오류 메시지)
컨트롤러(response.sendError( )) > 인터셉터 > 서블릿 > 필터 > WAS(sendError 호출 기록 확인)
커스텀 에러 페이지
기본 에러 페이지 대신 커스텀 에러 페이지를 제공해보자.
@Component
public class WebServerCustomizer implements WebServerFactoryCustomizer<ConfigurableWebServerFactory> {
@Override
public void customize(ConfigurableWebServerFactory factory) {
ErrorPage errorPage404 = new ErrorPage(HttpStatus.NOT_FOUND, "/error-page/404");
factory.addErrorPages(errorPage404);
}
}
404 오류가 발생하면, 에러 페이지 정보를 찾아 /errorpage/404
컨트롤러가 호출된다.
이때, 해당 오류와 그 자식 타입의 오류를 함께 처리한다.
이렇게 오류가 WAS 까지 전파되면, WAS 가 상태에 맞는 컨트롤러를 다시 호출한다.
@Controller
public class ErrorPageController {
@RequestMapping("/error-page/404")
public String errorPage404(HttpServletRequest request, HttpServletResponse response) {
return "error-page/404";
}
}
컨트롤러가 호출되면, error-page/404
뷰 템플릿을 화면에 렌더링하여 보여준다.
동작 흐름
컨트롤러(예외 발생) > 인터셉터 > 서블릿 > 필터 > WAS(/error-page/404 호출)
> 필터 > 서블릿 > 인터셉터 > 컨트롤러(/error-page/404) > View
WAS 까지 오류가 전파되면 서버 내부에서 다시 오류 페이지를 호출한다.
이때, 클라이언트는 서버 내부에서 발생하는 일을 알지 못한다.
이렇게 WAS 가 오류 페이지를 요청할 때, request 에 오류 정보를 넘겨준다.
getAttribute(jakarta.servlet.error.exception)
: 예외
getAttribute(jakarta.servlet.error.exception_type)
: 예외 타입
getAttribute(jakarta.servlet.error.message)
: 오류 메시지
getAttribute(jakarta.servlet.error.request_uri)
: 클라이언트 요청 URI
getAttribute(jakarta.servlet.error.servlet_name)
: 오류가 발생한 서블릿 이름
getAttribute(jakarta.servlet.error.status_code)
: HTTP 상태 코드
getDispatcherType()
: 요청구분
DispatcherType
서버 내부에서 에러 페이지를 호출할 때 필터나 인터셉터가 한번 더 호출되는 것은 비효율 적이다.
요청을 구분하여 특정 요청에 필터를 호출할 수 있다.
REQUEST
: 클라이언트 요청
ERROR
: 오류 요청
FORWARD
: 다른 서블릿이나 JSP 호출할 때
INCLUDE
: 다른 서블릿이나 JSP 의 결과를 포함할 때
ASYNC
: 서블릿 비동기 호출
필터에서 사용법
filterRegistrationBean.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ERROR);
이렇게 하면 클라이언트 요청과 에러 페이지 요청에서 필터가 호출된다.
DispatcherType.REQUEST 는 기본값으로, 생략 시 적용된다.
인터셉터에서 사용법
registry.excludePathPatterns("/error-page/**");
이렇게 하면 에러 페이지 경로일 때 인터셉터가 호출되지 않는다.
스프링 부트 에러 처리
스프링 부트는 에러 페이지를 만드는 과정 대부분을 자동으로 처리해 준다.
(WebServerCustomizer, ErrorPage, ErrorPageController 만들기 등)
ErrorPage 를 자동으로 등록하여 /error
라는 경로로 기본 에러 페이지를 설정하여,
예외가 발생하면 모든 오류를 /error
를 호출하도록 한다.
또한 BasicErrorController 라는 스프링 컨트롤러를 자동으로 등록하여,
ErrorPage 에서 등록한 /error
를 매핑하여 처리하는 BasicErrorController
컨트롤러를 자동으로 등록한다.
> 참고 <
에러 페이지를 자동으로 등록하는 역할은 ErrorMvcAutoConfiguration
클래스가 한다.
뷰 선택 우선순위
1. 뷰 템플릿
: resources/templates/error/500.html
: resources/templates/error/5xx.html
2. 정적 리소스 (static, public)
: resources/static/error/400.html
: resources/static/error/4xx.html
3. 적용 대상 없을 때 뷰 이름 (error)
: resources/templates/error.html
해당 경로 위치에 HTTP 상태 코드 이름의 뷰 파일을 넣어두면 된다.
이때, 4xx.html
이면 400 대 오류를 처리한다.
BasicErrorController
model 에 다음 정보를 담아서 뷰에 전달한다.
timestamp
: 오류 발생 시간
status
: HTTP 상태 코드
error
: 에러 유형
exception
: 예외 클래스
trace
: 예외의 상세 스택 트레이드
message
: 예외 메시지
errors
: Spring 의 BindingResult 객체에서 발생한 검증 오류 정보
path
: 예외가 발생한 URL 경로
오류 관련 내부 정보를 노출하는 것은 보안상의 문제가 있다.
따라서 BasicErrorController 에서 다음 정보를 model 에 포함할지 여부를 선택할 수 있다.
개발 서버
server.error.include-exception=true
server.error.include-message=on_param
server.error.include-stacktrace=on_param
server.error.include-binding-errors=on_param
운영 서버
server.error.include-exception=false
server.error.include-message=never
server.error.include-stacktrace=never
server.error.include-binding-errors=never
never
: 사용하지 않음
always
: 항상 사용
on_param
: 파라미터가 있을 때 사용
(ex. message=&errors=&trace=
)
on_param
은 디버그 시 문제를 확인하기 위해 개발 서버에서 사용할 수 있다. (운영 서버에서는 권장 X)
오류 관련 옵션
server.error.whitelabel.enabled=true
: 스프링 기본 오류 페이지 사용 여부
server.error.path=/error
: 글로벌 오류 페이지 경로
확장
ErrorController 인터페이스를 상속받아 구현하거나, BasicErrorController 를 상속받아 기능을 추가하면
에러 공통 처리 컨트롤러의 기능을 변경할 수 있다.
출처 | 스프링 MVC 2(김영한) - 인프런
'💠프로그래밍 언어 > Java' 카테고리의 다른 글
[Spring] 컨버터와 포맷터 (컨버전 서비스, 스프링 기본 제공 포맷터) (0) | 2025.04.06 |
---|---|
[Spring] API 에러 처리하는 방법, ExceptionResolver 와 @ControllerAdvice (0) | 2025.04.06 |
[Spring] 컨트롤러 공통 작업 자동화 (ArgumentResolver 의 활용) (0) | 2025.04.04 |
[Spring] 인터셉터란? + 요청 로그 인터셉터, 인증 체크 인터셉터 예시 (0) | 2025.04.04 |
[Spring] 필터란 ? + 요청 로그 필터, 인증 체크 필터 예시 (0) | 2025.04.04 |