서브릿이 예외를 처리하는 방식
서블릿 오류페이지 동작 과정
1. WAS(여기까지 전파) <- 필터 <- 서블릿 <- 인터셉터 <- 컨트롤러(예외발생)
2. WAS `/error-page/500` 다시 요청 -> 필터 -> 서블릿 -> 인터셉터 -> 컨트롤러(/error- page/500) -> View
- 위와 같이 예외가 발생해서 WAS까지 전파된다.
- WAS는 오류 페이지 경로를 찾아서 내부에서 오류 페이지를 호출한다. -> 이때 오류 페이지 경로로 필터,
서블릿, 인터셉터, 컨트롤러가 모두 다시 호출된다.
서블릿 예외 처리 - 필터
1. WAS(여기까지 전파) <- 필터 <- 서블릿 <- 인터셉터 <- 컨트롤러(예외발생)
2. WAS `/error-page/500` 다시 요청 -> 필터 -> 서블릿 -> 인터셉터 -> 컨트롤러(/error- page/500) -> View
- 오류가 발생하면 오류 페이지를 출력하기 위해 WAS 내부에서 다시 한번 호출이 발생한다.
- 이때 필터, 서블릿, 인터셉터도 모두 다시 호출된다. -> 비효율적이다.
- 서블릿은 이런 문제를 해결하기 위해 DispatcherType 이라는 추가 정보를 제공한다.
- DispatcherType
REQUEST : 클라이언트 요청
ERROR : 오류 요청
- WebConfig 에 위에 해당하는 설정을 할 수 있다.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Bean
public FilterRegistrationBean logFilter() {
FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<>();
filterRegistrationBean.setFilter(new LogFilter());
filterRegistrationBean.setOrder(1);
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.setDispatcherTypes(DispatcherType.REQUEST,DispatcherType.ERROR);
return filterRegistrationBean;
}
}
- 이렇게 두 가지를 모두 넣으면 클라이언트 요청은 물론이고, 오류 페이지 요청에서도 필터가 호출된다.
- 아무것도 넣지 않으면 기본 값이 DispatcherType.REQUEST 이다.
서블릿 예외 처리 - 인터셉터
- 인터셉터의 경우 Spring에서 지원해 주는 것이기 때문에 서블릿에서 지원해주는 필터와 달리 DispatcherType 가 없다.
- 하지만 excludePathPatterns 을 통해서 더 간편하게 구현할 수 있다.
- WebConfig 에서 위의 설정을 해줄 수 있다.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogInterceptor())
.order(1)
.addPathPatterns("/**")
.excludePathPatterns("/error-page/**");
}
}
- 위와 같이 설정하면 에러페이지의 경우 인터셉터가 적용되지 않는다.
- 동작과정은 아래와 같이 정리할 수 있다.
1. WAS(/error-ex, dispatchType=REQUEST) -> 필터 -> 서블릿 -> 인터셉터 -> 컨트롤러
2. WAS(여기까지 전파) <- 필터 <- 서블릿 <- 인터셉터 <- 컨트롤러(예외발생)
3. WAS 오류 페이지 확인
4. WAS(/error-page/500, dispatchType=ERROR) -> 필터(x) -> 서블릿 -> 인터셉터(x) -> 컨트롤러(/error-page/500) -> View
스프링 부트가 제공하는 오류페이지
- 스프링 부트는 아래와 같은 과정으로 오류페이지를 제공한다.
- ErrorPage 를 자동으로 등록한다. 이때 /error 라는 경로로 기본 오류 페이지를 설정한다.
- new ErrorPage("/error") , 상태코드와 예외를 설정하지 않으면 기본 오류 페이지로 사용된다.
- 서블릿 밖으로 예외가 발생하거나, response.sendError(...) 가 호출되면 모든 오류는 /error 를 호출하게 된다.
- 위와 같이 에러를 요청하면, 그 에러를 처리하는 컨트롤러가 필요한데, BasicErrorController 라는 스프링 컨트롤러를 자동으로 등록된다.
- ErrorPage 에서 등록한 /error 를 매핑해서 처리하는 컨트롤러다.
- 위와 같이 설정되므로 개발자는 다른 구현없이 오류 페이지만 만들어 놓으면 된다.
REFERENCES