전까지는 페이지 처리는 어찌저찌 필터와 인터셉터로 url을 변경해서 간단하게 처리가 가능했는데, API가 오류가 났을때는 어떻게 할까?! → 보통 api 각 오류 상황에 맞는 오류응답 세팅을 정하고, JSON으로 데이터를 보내주어야 한다. 끝판왕 먼저 말하자면 아무렇지 않게쓰던 @ExceptionHandler 인데…

그래도 서블릿과 스프링의 공통 에러처리 먼저 보고가자!

아래는 서블릿의 공통에러 처리이다. ResponseEntity<Map<String, Object>> 를 이용하여 메시지 컨버터가 동작하면서 클라이언트에 바로 (정확히는 HttpBody에) JSON형식으로 반환된다.

@RequestMapping의 produces = MediaType.APPLICATION_JSON_VALUE 는 HTPP Header의 accept의 값이 application/json일때 해당 메서드가 호출되는 것이다.

    @RequestMapping(value = "/error-page/500", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<Map<String, Object>> errorPage500Api(
            HttpServletRequest request, HttpServletResponse response) {

        log.info("API errorPage 500");

        Map<String, Object> result = new HashMap<>();
        Exception ex = (Exception) request.getAttribute(ERROR_EXCEPTION);
        result.put("status", request.getAttribute(ERROR_STATUS_CODE));
        result.put("message", ex.getMessage());

        Integer statusCode = (Integer) request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
        return new ResponseEntity<>(result, HttpStatus.valueOf(statusCode));
    }

다음은 스프링의 기본적인 API에러 처리이다. 그전에 에러페이지 처리에서 Spring의 BasicErrorController 가 에러가 나면 “/error” url을 기본으로 호출한다.. BasicErrorController는 페이지 처리뿐만 아니라 API에러도 함께 처리중이다.

아래는 BasicErrorController 인터페이스를 들어가보면 오버로딩 되어있는 함수이다. 딱~ 봐도 첫번 errorHtml()함수는 정적파일을 반환해줄 메서드이고(ModelAndView 반환중!) 두번째 매서는 ResponseEntity<Map<String,Object> 를 반환해주면서 HTTP Body에 JSON형식을 반환해줄 매서드이다.

@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse
response) {}

@RequestMapping
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {}

스프링 부트는 BasicErrorController 가 제공하는 기본 정보들을 활용해서 오류 API를 생성해준다.

image.png

물론 오류 메시지는 이렇게 막 추가하면 보안상 위험할 수 있다. 간결한 메시지만 노출하고, 로그를 통해서 확인하자.