-
Spring MVC (2) - 예외 처리와 오류 페이지Web/Spring 2023. 11. 21. 22:53
1. 서블릿 예외처리
- 서블릿은 2가지 방식으로 예외 처리를 지원한다. (Exception, response.sendError(HTTP 상태코드, 오류메시지))
1.1 Exception
- 자바의 경우 try-catch를 하지 못하고 main쓰레드까지 예외가 던져지면, 예외 정보 출력 후 쓰레드 종료
- 웹 애플리케이션의 경우 예외를 잡지 못하는 경우 인터셉터 -> 서블릿 -> 필터 -> WAS 까지 전파됨
@GetMapping("/error-ex") public void errorEx() { throw new RuntimeException("예외 발생!"); }
- 위와 같이 예외를 발생시키면, 톰캣 기본 오류 화면을 볼 수 있다. (HTTP Status 500 - Internal Server Error)
- Exception의 경우 서버 내부에서 처리할 수 없는 오류가 발생한 것으로 보고 HTTP 상태 코드 500을 반환한다.
1.2 response.sendError(HTTP 상태 코드, 오류 메시지)
- 당장 예외 발생 X
- 서블릿 컨테이너에 오류 발생을 전달할 수 있다.
- 컨트롤러 -> 인터셉터 -> 서블릿 -> 필터 -> WAS (sendError 확인)
- sendError에 전달된 에러를 보고 오류 페이지를 보여줌
2. 서블릿 예외 처리 - 오류 화면 제공
- Exception 혹은 sendError()시 상황에 따라 오류 처리 기능 제공한다.
- 스프링 부트를 통해서 서블릿 오류 페이지를 등록해보자.
public class WebServerCustomizer implements WebServerFactoryCustomizer<ConfigurableWebServerFactory> { @Override public void customize(ConfigurableWebServerFactory factory) { ErrorPage errorPage404 = new ErrorPage(HttpStatus.NOT_FOUND, "/errorpage/404"); ErrorPage errorPage500 = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error-page/500"); ErrorPage errorPageEx = new ErrorPage(RuntimeException.class, "/errorpage/500"); factory.addErrorPages(errorPage404, errorPage500, errorPageEx); } }
- 위와 같이 에러 페이지를 등록할 수 있다.
- 오류 페이지는 예외를 다룰 때 해당 예외의 자식 타입의 오류도 함께 처리한다.
2.1 오류 처리 컨트롤러
@Controller public class ErrorPageController { @RequestMapping("/error-page/404") public String errorPage404(HttpServletRequest request, HttpServletResponse response) { log.info("errorPage 404"); return "error-page/404"; } @RequestMapping("/error-page/500") public String errorPage500(HttpServletRequest request, HttpServletResponse response) { log.info("errorPage 500"); return "error-page/500"; } }
3. 서블릿 예외 처리 - 오류 페이지 작동 원리
- Exception 혹은 sendError()이 호출되면, 설정된 오류 페이지를 찾는다.
- WAS는 예외를 처리하는 오류페이지 정보를 확인한다.
(new ErrorPage(RuntimeException.class, "/error-page/500")
- 내부적으로 해당 url을 다시 요청한다
(필터 -> 서블릿 -> 인터셉터 -> 컨트롤러 (/error-page/500) -> 뷰
* 중요한 점은 클라이언트는 이런 내부 호출을 전혀 모름 (오류 페이지를 찾기 위한 추가 호출)
또한, 내부 재호출시에도 필터, 인터셉터 등 다시 호출 됨을 확인 할 수 있다.
3.1 오류 정보 추가
- WAS는 단순히 재요청 뿐 아니라 request등에 추가 정보를 넘겨준다.
(필요시 사용 가능하다)
- RequestDispatcher 클래스에 상수로 정의되어 있다.
- request의 getDispatcherType은 중요하게 쓰임!
4. 서블릿 예외 처리 - 필터
- WAS의 내부 호출 시 필터,서블릿,인터셉터가 다시 호출 된다.
- 근데 필터나 인터셉터등은 대부분 정상 호출에서 이미 처리됨 -> 재호출은 비효율적
- 따라서 서버는 클라이언트의 정상호출과 에러 페이지 호출을 구분해야함
(DispatcherType을 제공함)
4.1 Dispatcher Type
- 정상호출 시 REQUEST, 에러 페이지 호출 시 ERROR
- > 뿐만 아니라, INCLUDE,ASYNC,FORWARD 등이 있음
@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를 통해 지정할 수 있다.
5. 서블릿 예외 처리 - 인터셉터
- 인터셉터의 경우 서블릿의 기능이 아니라, 스프링이 제공하는 기능이다.
- 따라서 DispatcherType과는 무관하게 작동한다.
- 다만, 인터셉터가 처리하는 경로는 추가하거나 제외하기 쉽다 (excludePathPatterns를 사용하자)
@Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LogInterceptor()) .order(1) .addPathPatterns("/**") .excludePathPatterns( "/css/**", "/*.ico" , "/error", "/error-page/**" //오류 페이지 경로 );
6 스프링 부트 - 오류 페이지
- 스프링 부트는 ErrorPage, ErrorPageController 만드는 작업을 기본으로 제공함
- 이때 ErrorPage 등록 시 /error로 url을 매핑한다.
- 모든 Exception, 혹은 response.sendError을 /error하나로 처리한다.
- 이때 컨트롤러로 BasicErrorController이 사용된다.
ErrorPage에서 등록한 /error을 매핑해서 처리한다.
* BasicErrorController에 기본 로직이 모두 개발되어 있다.
- BasicErrorController가 제공하는 룰과 우선순위에 따라 오류 페이지 등록하자
(정적 HTML - > 정적 리소스 자리, 뷰 템플릿 -> 동적 리소스 자리)
6.1 뷰 선택 우선순위
- 해당 경로 위치에 HTTP 상태 코드 이름의 뷰 파일을 넣어두자
- 5xx, 4xx로 두면, 500 혹은 400대 오류를 모두 처리해준다.
7. 스프링 부트 - 오류 페이지2
- BasicErrorController는 오류 정보를 model에 담아서 전달한다. (message,path, status 등)
- 뷰 템플릿은 이 값을 활용해서 출력할 수 있다.
- 또한 application.properties를 통해 model에 포함할 오류 정보를 선택할 수 있다.
#application.properties server.error.include-exception=false #: exception 포함 여부( true , false ) server.error.include-message=never #: message 포함 여부 on_param 등과 같이 파라미터 있을 때에만 제공할 수 있다. server.error.include-stacktrace=never #: trace 포함 여부 server.error.include-binding-errors=never #: errors 포함 여부 server.error.whitelabel.enabled=true # 오류 페이지 못찾으면, whirelabel 오류 페이지 적용 server.error.path=/error # 스프링이 자동 등록하는 글로벌 오류 페이지 경로와 BasicErrorController 경로 함께 사용됨
- on_param을 사용하면, 파라미터 정보가 노출됨 -> 디버그시 유용 (개발 서버에서만 사용하자)
* 에러 공통 처리 컨트롤러를 변경하고 싶으면, ErrorController 인터페이스를 상속 받아서 구현하거나
BasicErrorController를 상속 받아서 기능을 추가하자
'Web > Spring' 카테고리의 다른 글
Spring MVC 2 - API 예외 처리 @ExceptionResolver (0) 2023.11.22 Spring MVC 2 - API 예외 처리 HandlerExceptionResolver (0) 2023.11.22 Spring MVC (2) - 스프링 포맷터 (0) 2023.11.21 Spring MVC(2) - 스프링 타입 컨버터 (0) 2023.11.21 SpringMVC 2 - 서블릿 필터와 인터셉터 (0) 2023.11.15