웹 사이트에서 예외는 언제나 발생할 수 있기때문에 에러에 대한 페이지 또한 관리가 필요합니다. 기본적으로 생각할 수 있는 404, 500등이 생각이 납니다. 기존 예외 페이지를 관리하는 방법은 web.xml에 에러코드에 대한 페이지를 등록하는 방법이 있는데 스프링 부트에서 제공되는 기능으로 처리해보겠습니다.
@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);
}
}
WebServerFactoryCustomizer를 상속받은 클래스에 에러코드에 대한 제공 된 에러페이지들을 만든 뒤 등록한 코드입니다.
각 에러에 두번째 인자는 페이지 위치가 아니라 매핑주소라서 해당 매핑주소에 대한 컨트롤러도 만들어줍니다.
@Slf4j
@Controller
public class ErrorPageController {
@GetMapping("/error-page/404")
public String errorPage404(HttpServletRequest request, HttpServletResponse response){
log.info("errorPage 404");
return "error-page/404";
}
@GetMapping("/error-page/500")
public String errorPage500 (HttpServletRequest request, HttpServletResponse response){
log.info("errorPage 500");
return "error-page/500";
}
}
위에서 등록된 에러가 발생하면 지정한 매핑주소로 이동을 하여 아래 컨트롤러에 등록된 return 페이지가 화면에 보이게 됩니다.
결국 한번에 요청에 두번이 되어 요청이 두번이 되는데 그렇게 된다면 설정해놓은 필터나 인터셉터가 두번 실행된다는 말입니다. 사실 그렇게 되도 상관이 없을수도 있고 두번 실행되면 안되는 요청이 있다면 두번의 요청에 대해 클라이언트의 요청인지 에러가 발생하여 요청이 된 서버내부의 요청인지 구분을 하기 위해 스프링 부트에선 DispatcherType을 사용하여야 합니다.
request.getDispatcherType()
클라이언트 요청인 경우 : REQEUST
에러가 발생하여 서버내부의 요청인 경우 : ERROR
Filter
@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;
}
}
필터를 만들었는데 맨 마지막 부분에 setDispatcherTypes를 REQUEST와 ERROR를 등록했는데 클라이언트에 요청인지 에러 서버내부 요청인지 확인하여 두 요청 모두 적용한다는 의미입니다. 아무것도 지정하지 않는다면 기본값으로 REQUEST이므로 따로 지정하지 않으면 에러요청은 작동을 하지 않습니다.
Interceptor
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogInterceptor())
.order(1)
.addPathPatterns("/**")
.excludePathPatterns("/css/**","*.icon","/error","/error-page/**");
}
}
인터셉터는 필터처럼 dispatcherType을 구분할 수 있는 기능은 없지만 강력한 excludePathPatterns를 사용하여 에러에 대한 요청매핑을 제외하여 구분이 가능합니다.
이제 스프링 부트에서 제공되는 편리한 기능으로 오류페이지를 관리해보겠습니다.
위와 같은 방식은 WebServerCustomizer를 만들고 에러 발생시 매핑될 컨트롤러도 만들었지만 스프링 부트에서는 이런 기능을 기본으로 제공해 줍니다. 에러가 발생하면 ErrorPage를 자동으로 생성하여 /error라는 경로에 에러코드와 일치하는 파일을 화면에 뿌려줍니다.
404에러일때 : /resources/templates/error/404.html
400번 에러일때 : /resources/templates/error/4xx.html
500에러일때 : /resources/templates/error/500.html
에러 파일의 경로는 이미 규칙이 있으므로 templates/error경로에 지정해주어야 합니다.
이런 과정을 대신 해주는 기능이 BasicErrorController인데 여기서 에러페이지로 이동할때 에러에 관한 많은 정보를 담아서 보내줍니다.
<ul>
<li>오류 정보</li>
<ul>
<li th:text="|timestamp: ${timestamp}|"></li>
<li th:text="|path: ${path}|"></li>
<li th:text="|status: ${status}|"></li>
<li th:text="|message: ${message}|"></li>
<li th:text="|error: ${error}|"></li>
<li th:text="|exception: ${exception}|"></li>
<li th:text="|errors: ${errors}|"></li>
<li th:text="|trace: ${trace}|"></li>
</ul>
</li>
</ul>
생성한 에러페이지에 위의 코드를 넣어보면 BasicErrorController에서 보내준 에러 정보들을 확인하실수 있습니다.
당장 실행해보면 null로 반환되는 값들이 존재하는데 예외에 대한 메세지가 노출이 되는건 위험할 수 있기 때문에 properties에 노출을 허용하게 된다면 가능합니다.
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 ` 포함 여부
굳이 넣지 않는게 좋을것 같습니다.
'spring' 카테고리의 다른 글
API 예외처리 - HandlerExceptionResolver (0) | 2024.06.03 |
---|---|
Validation 정리 (0) | 2024.06.02 |
Spring Interceptor (0) | 2024.06.01 |
Spring Filter (0) | 2024.06.01 |
Session Cookies (0) | 2024.05.31 |