이전에 학습했던 스프링 제공 예외 페이지 컨트롤러 BasicErrorController에 들어가 보면 /error 동일한 경로를 처리하는 errorHtml() , error() 두 메서드를 확인할 수 있다.
내부 요청을 매핑하는 스프링 부트 기본 제공 컨트롤러
요청에 따라 하나는 html을 반환하고 하나는 json을 반환한다.
스프링 부트가 이미 JSON으로 데이터를 반환해야하는 경우도 구현해 놓은것이다.
errorHtml() : 클라이언트 요청의 Accept 해더 값이 text/html 인 경우에는 errorHtml() 을 호출해서 view를 제공한다.
error() : 그외 경우에 호출되고 ResponseEntity 로 HTTP Body에 JSON 데이터를 반환한다.
이때 아래와 같이 예외 관련 정보를 Json으로 반환한다.
{
"timestamp": "2021-04-28T00:00:00.000+00:00",
"status": 500,
"error": "Internal Server Error",
"exception": "java.lang.RuntimeException",
"trace": "java.lang.RuntimeException: 잘못된 사용자\n\tat
hello.exception.web.api.ApiExceptionController.getMember(ApiExceptionController
.java:19...,
"message": "잘못된 사용자",
"path": "/api/members/ex"
}
즉, 요청 HTTP Header 의 Accept 값이 text/html 가 아니고 application/json 일때 html 오류 페이지 대신에 json으로 예외 정보를 반환 하도록하는 메서드가 이미 정의 되어있다.
스프링이 제공하는 BasicErrorController는 이미 요청 Http Header의 Accept가 text/html 일때와 application/json일때를 처리하는 컨트롤러들이 각각 정의되어있는 것이다.
BasicErrorController 는 HTML 페이지를 제공하는 경우에는 매우 편리하다.
/error 경로에 매핑한 html을 보여주기만 하면 되기때문
그런데 API 오류 처리는 다른 차원의 이야기이다. API 마다, 각각의 컨트롤러나 예외마다
서로 다른 응답 결과를 출력해야 할 수도 있다.
단순히 오류관련 정보나 페이지를 반환하는게 아니라 API에 따라서 각기 다른 JSON 데이터를 반환해야한다.
즉, BasicErrorController가 API 오류 처리를 하는 메서드를 지원하긴 하지만 이 메서드 기능 만으로는 부족하다.
@ExceptionHandler를 이용하면 BasicErrorController를 확장해서 예외마다 각기 다른 JSON 데이터를 반환하도록 할수있다.
아래서 설명한다.
HandlerExceptionResolver (aka. ExceptionResolver)
BasicErrorController는 오류페이지 컨트롤러로 다음과 같은 동작 절차를 거친다고 설명했었다.
1. WAS(여기까지 전파) <- 필터 <- 서블릿 <- 인터셉터 <- 컨트롤러(예외발생: response.sendError())
2. WAS 예외 페이지 정보 확인
3. WAS (`/error-page/500` 다시 요청) -> 필터 -> 서블릿 -> 인터셉터 -> *컨트롤러(/errorpage/500) -> View
기본적으로 Html과 Json을 다 컨트롤 할수있긴하지만 Json의 경우 그 기능도 부족하고 에초에 WAS까지 예외가 올라갔다가 다시 내려오는 과정 자체가 비효율적으로 느껴진다.
스프링은 이를 해결하고자 HandlerExceptionResolver 줄여서 ExceptionResolver를 도입했다.
ExceptionResolver 적용 전후 동작 비교
기존에는 예외가 발생하면 WAS까지 예외가 전달 되었지만
ExceptionResolver를 적용하면 디스패쳐 서블릿이 예외를 WAS로 던지지 않고 ExceptionResolver에게 예외를 해결하도록 한다.
[핵심!]
즉, WAS까지 예외가 전달되던 기존과 달리 ExceptionResolver로 예외를 중간에서 받아서 처리하고 WAS에겐 정상흐름을 반환 함으로써 예외를 정상처리 된것으로 만드는것이 목적이다.
예외가 WAS까지 올라가지 않는다.
WAS까지 예외를 보내지않고 예외를 이곳에서 모두 처리할 수 있다는 것
WAS는 예외 발생 여부를 모른다.
또한, API 데이터 , 뷰 템플릿 , 상태코드 변환 등을 자유롭게 적용할수있어서 디테일한 응답을 생성할수있다.
Controller처럼 HTML,JSON,responseEntity 등 모두 반환할수있다.
직접 ExceptionResolver 구현하기
ExceptionResolver 클래스를 정의해서 예외 처리 로직을 짜고 ,WebConfig에 등록해서 사용한다.
//MyHandlerExceptionResolver.java
@Slf4j
public class MyHandlerExceptionResolver implements HandlerExceptionResolver {
//예외처리 로직
}
//WebConfig.java
@Override
public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver>
resolvers) {
resolvers.add(new MyHandlerExceptionResolver()); //등록
}
'개발 일지 > Spring' 카테고리의 다른 글
스프링 AOP StackOverflowError (feat.스프링 AOP 동작원리) (0) | 2022.02.10 |
---|---|
스프링 부트가 기본으로 제공하는 HandlerExceptionResolver (0) | 2022.01.24 |
Spring에서 json 통신을 다루기 ResponseEntity, @ResponseBody (0) | 2022.01.17 |
@RequestBody, @ModelAttribute , @RequestParam , 추가로 @PathVariable (0) | 2022.01.13 |
스프링으로 서블릿(Servlet)을 다룬다는 것 (0) | 2022.01.03 |