웹 애플리케이션
사용자 요청별로 별도의 쓰레드가 할당되고, 서블릿 컨테이너 안에서 실행된다.
애플리케이션에서 예외를 잡지 못하고, 서블릿 밖으로 까지 예외가 전달되면 WAS까지 예외가 전달된다.
WAS <- 필터 <- 서블릿 <- 인터셉터 <- 컨트롤러(예외발생)
response.sendError()를 호출하면, WAS에서 클라이언트에게 응답 전에 response에 sendError()가 호출되었는지 확인 후, 오류가 발생함을 인지하고 오류 페이지를 보여주게 된다.
컨트롤러에서 예외 발생
WAS(sendError 호출 확인) <- 필터 <- 서블릿 <- 인터셉터 <- 컨트롤러(예외발생, response.sendError())
오류 페이지 요청
WAS
/error-page/500
다시 요청 -> 필터 -> 서블릿 -> 인터셉터 -> 컨트롤러(/errorpage/
500) -> View
여기에서 오류 페이지를 요청할 때 필터 인터셉터가 다시 호출되는 것이 매우 비효율적이기 때문에,
클라이언트로 부터 발생한 요청인지, 오류 페이지를 출력하기 위한 내부 요청인지 구분할 수 있어야 한다.
이를 해결하기 위해 서블릿은 DispatcherType이라는 추가 정보를 제공해준다.
필터에 setDispatcherTypes의 파라미터로 DispatcherType.REQUEST만 사용하면 ERROR에 대해서는 필터가 호출되지 않는다.
@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과는 무관하게 항상 호출된다.
excludePathPatterns를 이용해 오류 페이지 경로를 제외시키면 된다.
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogInterceptor())
.order(1)
.addPathPatterns("/**")
//오류 페이지 경로 ("/error")
.excludePathPatterns( "/css/**", "/*.ico", "/error", "/error-page/**");
}
스프링 부트가 이런 과정을 모두 기본으로 제공해준다.
따라서 개발자는 다음 경로에 오류 페이지들만 넣어두면 된다.
뷰 템플릿
정적 리소스(static, public)