서블릿 예외 처리

@Controller
public class ServletExController {
 @GetMapping("/error-ex")
 public void errorEx() {
	 throw new RuntimeException("예외 발생!");
 }
 @GetMapping("/error-404")
	 public void error404(HttpServletResponse response) throws IOException { response.sendError(404, "404 오류!");
 }
 @GetMapping("/error-500")
 public void error500(HttpServletResponse response) throws IOException {
	 response.sendError(500);
 }
}

sendError 흐름

WAS(sendError 호출 기록 확인) <- 필터 <- 서블릿 <- 인터셉터 <- 컨트롤러 (response.sendError())

response 내부에 오류 코드를 저장하고 그에 맞춰 오류 페이지를 보여준다.

오류 페이지 등록

@Component
public class WebServerCustomizer implements WebServerFactoryCustomizer<ConfigurableWebServerFactory> {

    @Override
    public void customize(ConfigurableWebServerFactory factory) {

        ErrorPage errorPage404 = new ErrorPage(HttpStatus.NOT_FOUND, "/error-page/404");
        ErrorPage errorPage500 = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error-page/500");
        ErrorPage errorPageEx = new ErrorPage(RuntimeException.class, "/error-page/404");
        factory.addErrorPages(errorPage404,errorPage500,errorPageEx);
    }
}

웹 브라우저(클라이언트)는 서버 내부에서 이런 일이 일어나는지 전혀 모른다는 점이다. 오직 서버 내부에서 오류 페이지를 찾기 위해 추가적인 호출을 한다.

필터

결국 클라이언트로 부터 발생한 정상 요청인지, 아니면 오류 페이지를 출력하기 위한 내부 요청인지 구분할 수 있어야 한다. 서블릿은 이런 문제를 해결하기 위해 DispatcherType 이라는 추가 정보를 제공한다.

@Configuration
public class WebConfig implements WebMvcConfigurer {
	@Bean
    public FilterRegistrationBean logFilter(){
        FilterRegistrationBean<Filter> filterFilterRegistrationBean = new FilterRegistrationBean<>();
        filterFilterRegistrationBean.setFilter(new LogFilter());
        filterFilterRegistrationBean.setOrder(1);
        filterFilterRegistrationBean.addUrlPatterns("/*");
        filterFilterRegistrationBean.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ERROR);
        return filterFilterRegistrationBean;
    }

}

filterFilterRegistrationBean.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ERROR);

클라이언트 요청, 오류 페이지 요청에 필터를 호출한다.

기본 값으로 DispatcherType.REQUEST 가 들어가 있으므로 오류 페이지 경로에 필터를 적용하지 않으면 기본 값을 그대로 사용한다.

인터셉터

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LogInterceptor())
                .order(1)
                .addPathPatterns("/**")
                .excludePathPatterns("/css/**", "*.ico", "/error", "/error-page/**");
    }
}

.excludePathPatterns("/css/**", "*.ico", "/error", "/error-page/**");

오류 페이지 경로를 제외 시켜주었다.

스프링 부트 예외 처리

WebServerCustomizer를 만들고 예외 종류에 따라서 ErrorPage를 추가하고 예외 처리 용 컨트롤러 ErrorPageController를 만드는 과정을 기본으로 제공.

뷰 선택 우선순위

BasicErrorController의 처리 순서

  1. 뷰 템플릿

resources/templates/error/500.html

resources/templates/error/5xx.html

  1. 정적 리소스( static , public )

resources/static/error/400.html

resources/static/error/404.html

resources/static/error/4xx.html

  1. 적용 대상이 없을 때 뷰 이름( error )

resources/templates/error.html