Spring MVC/03.예외 처리

[spring 예외 처리] 04. 프로그래밍적인 404 처리

  • -
반응형

마지막으로 웹 오류에서 조금은 독특한 404 오류 처리에 대해서 살펴보자. 404 오류는 다른 오류와 달리 기본적으로 @Controller를 탈 필요가 없기 때문에 Exception으로 처리되지 않는 특성이 있다. 

그럼 404 상황을 Exception으로 만들어서 처리할 수 있을까?

 

legacy

 

@ControllerAdvide에서 처리

404를 프로그래밍적으로 처리하고 싶다면 404 발생 시 예외를 발생시키도록 설정해야 한다.(기본적으로 404는 exception 상황이 아니다.) 이를 위해 web.xml에서 DispatcherServlet을 등록할 때 throwExceptionIfNoHandlerFound 초기화 파라미터를 true로 설정한다.

<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/config/servlet-context.xml</param-value>
    </init-param>
    <init-param>
        <param-name>throwExceptionIfNoHandlerFound</param-name>
        <param-value>true</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    <async-supported>true</async-supported>
</servlet>

이제 404 상황이 발생하면 NoHandlerFoundException이 발생하므로 다른 예외와 마찬가지로 처리하면 된다.

 

SpringBoot

 

BasicErrorController 활용

BasicErrorController는 상태 코드에 따라서 오류 페이지를 연결한다.  404 발생 시 그 상태 코드가 @Controller에게 전달되기 때문에 다음과 같이 NOT_FOUND일 경우의 처리만 해주면 된다.

@Controller
public class MyErrorController extends BasicErrorController {
  @Override
  public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) { 
    ModelAndView mnv = super.errorHtml(request, response);
    
    HttpStatus hs = getStatus(request);
    switch (hs) {
      case NOT_FOUND:
      mnv.setViewName("/error/404");
      break;
    default:
      mnv.setViewName("/error/500");
      break;
    }
    return mnv;
  }

 

@ControllerAdvice 활용

다음으로 SpringBoot에서 @ControllerAdvice를 활용하는 방법인데 사실 이 방법은 개인적으로 사용하지 말았으면 하는 방법이다.

spring boot @Controller단에서 404를 예외로 받으려면 application.properties에 다음의 설정을 추가해야 한다.

#404 상황에서 예외를 발생시킬 것인지
spring.mvc.throw-exception-if-no-handler-found=true

 

일단 @ControllerAdvice는 statuc code가 아닌 Exception 기반으로 동작한다. 그런데 application.properties의 if-no-handler-found는 사실 404를 처리하는것이 아니라 글자 그대로 handler가 발견되지 않았을 때 예외를 발생시켜라는 설정이다. 그런데 SpringBoot에서는 404 상황에서 적합한 Handler를 찾지 못하면 ResourceHttpRequestHandler가 할당된다.! 결국 예외가 발생하지 않는다.

따라서 예외가 발생하지 않고 이를 처리하기 위해 추가로 아래의 설정이 필요하다.

spring.web.resources.add-mappings=false

 

이렇게 두 개의 설정을 추가하면 404 상황에서 예외가 발생하고 @ControllerAdvice에서 처리가 가능하다.

그런데 이렇게 하면 또 여러가지 부가적인 문제가 발생한다.

1. css, js, 심지어 fabicon이 없는 상황에서도 NoHandlerFoundException이 발생한다.(정적 resource를 매핑하지 못하기 때문이다.)

WARN 20788 --- [nio-9090-exec-2] o.s.web.servlet.PageNotFound             : No mapping for GET /abc
WARN 20788 --- [nio-9090-exec-2] o.s.web.servlet.PageNotFound             : No handler found for GET /abc
WARN 20788 --- [nio-9090-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.servlet.NoHandlerFoundException: No handler found for GET /abc]

이 녀석들을 다시 등록해주는 과정이 필요해진다.

2. ResourceHttpRequestHandler를 사용하는 녀석들(Swagger 등)을 위한 별도의 설정이 필요하다.

public class SwaggerConfig implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("swagger-ui.html")
                .addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/");
    }
}

 

이처럼 오히려 신경써줘야 할 내용들이 더 많아진다.

따라서 404를 Exception 타입으로 처리하는 것 보다는 HttpStatus 기반으로 처리하는 것이 훨씬 유리하다.

 

반응형
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.