ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 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은 중요하게 쓰임! 

    출처: 스프링 MVC 2 (김영한) -인프런

     

    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 뷰 선택 우선순위

     

    출처: 스프링 MVC 2 (김영한) -인프런

     

     

    - 해당 경로 위치에 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를 상속 받아서 기능을 추가하자 

Designed by Tistory.