스프링/4. 스프링 MVC-2

72. 스프링 내부에서 발생하는 예외를 처리해주는 Resolver

sdafdq 2023. 9. 15. 22:26

자동등록 됨.

DefaultHandlerExceptionResolver라고 

 

 

보통 파라미터 바인딩 시점에서 타입이 맞지 않으면 내부에서 TypeMismatchException이 발생하는데, 

이게 원래는 컨트롤러에서 발생한 에러이기 때문에 500에러로 올라간다.

근데 사실 저 TypeMismatchException 대부분은 클라이언트가 정보를 잘못 입력했기 때문에 발생하는거다.

 

@GetMapping("/api/default-handler-ex")
public String defaultException(@RequestParam Integer data){
    return "ok";
}

컨트롤러에 이렇게 해 봤다.

그냥 숫자를 받고 응답으로 ok라고 보내주는 거다. 내가 요청헤더 acception을 application/json으로  해놔서 그냥 그렇게 올거다.

json형태로 요청하긴 했는데 그냥 return 자체가 뭔가 key:value 형식의 json이 아니면 걍 ok 텍스트로 오는 느낌이네.

 

여튼 저 상태에서 ?data=123 해서 제대로 숫자 넣으면 ok 라고 딱 이렇게 오고,

?data=qwer 등 숫자가 아닌 걸 넣으면 에러가 발생했다고 나오는데, 이게 컨트롤러에서 파라미터 바인딩하다가 타입 안 맞아서 난 오류인데도 불구하고 400(Bad Request)오류가 나온다.

메시지도 내가 현재는 보이게 해 놨는데(원래 보안때문에 응답에 같이 보내게끔 하면 안됨.),

Failed to convert value of type 'java.lang.String' to required type 'java.lang.Integer'; For input string: \"asdf\"",

이렇게 나온다.

 

누군가가 친절히 상태코드도 클라이언트의 문제라고 바꿔주고, 메시지도 자세히 넣어줬다.

 

이걸 하는 애가 DefaultHandlerExceptionResolver이다. 스프링 내의 오류들을 자주 있는 거, 아니 굉장히 많은 종류의 오류들을 얘가 처리해 준다. 저기 안에 굉장히 많은 오류의 처리에 대해 정의되어 있다.

 

 

다음이 실제 DefaultHandlerExceptionResolver 안에 있는 코드인데,

@Override
@Nullable
protected ModelAndView doResolveException(
        HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {

    try {
        // ErrorResponse exceptions that expose HTTP response details
        if (ex instanceof ErrorResponse errorResponse) {
            ModelAndView mav = null;
            if (ex instanceof HttpRequestMethodNotSupportedException theEx) {
                mav = handleHttpRequestMethodNotSupported(theEx, request, response, handler);
            }
            else if (ex instanceof HttpMediaTypeNotSupportedException theEx) {
                mav = handleHttpMediaTypeNotSupported(theEx, request, response, handler);
            }
            else if (ex instanceof HttpMediaTypeNotAcceptableException theEx) {
                mav = handleHttpMediaTypeNotAcceptable(theEx, request, response, handler);
            }
            else if (ex instanceof MissingPathVariableException theEx) {
                mav = handleMissingPathVariable(theEx, request, response, handler);
            }
            else if (ex instanceof MissingServletRequestParameterException theEx) {
                mav = handleMissingServletRequestParameter(theEx, request, response, handler);
            }
            else if (ex instanceof MissingServletRequestPartException theEx) {
                mav = handleMissingServletRequestPartException(theEx, request, response, handler);
            }
            else if (ex instanceof ServletRequestBindingException theEx) {
                mav = handleServletRequestBindingException(theEx, request, response, handler);
            }
            else if (ex instanceof MethodArgumentNotValidException theEx) {
                mav = handleMethodArgumentNotValidException(theEx, request, response, handler);
            }
            else if (ex instanceof NoHandlerFoundException theEx) {
                mav = handleNoHandlerFoundException(theEx, request, response, handler);
            }
            else if (ex instanceof AsyncRequestTimeoutException theEx) {
                mav = handleAsyncRequestTimeoutException(theEx, request, response, handler);
            }

            return (mav != null ? mav :
                    handleErrorResponse(errorResponse, request, response, handler));
        }

        // Other, lower level exceptions

        if (ex instanceof ConversionNotSupportedException theEx) {
            return handleConversionNotSupported(theEx, request, response, handler);
        }
        else if (ex instanceof TypeMismatchException theEx) {
            return handleTypeMismatch(theEx, request, response, handler);
        }
        else if (ex instanceof HttpMessageNotReadableException theEx) {
            return handleHttpMessageNotReadable(theEx, request, response, handler);
        }
        else if (ex instanceof HttpMessageNotWritableException theEx) {
            return handleHttpMessageNotWritable(theEx, request, response, handler);
        }
        else if (ex instanceof BindException theEx) {
            return handleBindException(theEx, request, response, handler);
        }
    }
    catch (Exception handlerEx) {
        if (logger.isWarnEnabled()) {
            logger.warn("Failure while trying to resolve exception [" + ex.getClass().getName() + "]", handlerEx);
        }
    }

굉장히 많은 종류의 예외를 받아서 대응한다.

 

 

물론, 400오류 뿐 아니라 500오류도 있다.

뭐랄까 좀더 자세히? 맞는? 오류코드를 넣어준다.