Written by
Sunwoo Han
on
on
API 예외 처리
스프링 MVC 2편 - 백엔드 웹 개발 활용 기술을 공부하고 정리하는 포스트입니다.
🏷 API 예외 처리
API의 경우 어떻게 예외 처리를 할까
- 오류 페이지는 단순히 고객에게 오류 화면을 보여주고 끝
→ API는 각 오류 상황에 맞는 오류 응답 스펙을 정하고, JSON으로 데이터를 내려줌
✔️ 스프링 부트 기본 오류 처리
BasicErrorController
@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) { }
@RequestMapping
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) { }
errorHtml()
produce = MediaType.TEXT_HTML_VALUE
:
클라이언트 요청의 Accept 헤더 값이text/html
인 경우에는errorHtml()
을 호출해서 view를 제공
error
- 그 외 경우
ResponseEntity
로 HTTP Body에 JSON 데이터를 반환
- 그 외 경우
✔️ HTML 페이지 vs API 오류
-
스프링 부트가 제공하는
BasicErrorController
는 HTML 페이지를 제공하는 경우에는 매우 편리
→ 4xx, 5xx 등등 모두 잘 처리해줌 -
하지만 API 오류 처리는 다른 차원의 이야기!! → API 마다, 각각의 컨트롤러나 예외마다 서로 다른 응답 결과를 출력해야 할 수도 있음
- 매우 세밀하고 복잡함
- 따라서 이 방법은 HTML 화면을 처리할 때 사용하고, API는 오류 처리는
@ExceptionHandler
를 사용!!
❗️ BasicErrorController를 확장해서 JSON 오류 메시지를 변경할 수 있다
🏷 HandlerExceptionResolver 활용
- 스프링 MVC는 컨트롤러(핸들러) 밖으로 예외가 던져진 경우 예외를 해결, 동작을 정의할 수 있는 방법을 제공
HandlerExceptionResolver
를 사용
📌 참고
ExceptionResolver
로 예외를 해결해도postHandle()
은 호출되지 않는다.
🏷 @ExceptionHandler
BasicErrorController
를 사용하거나HandlerExceptionResolver
를 직접 구현하는 방식은 API 예외를 다루기 어려움
✔️ API 예외처리의 어려운 점
HandlerExceptionResolver
→ModelAndView
를 반환- API 응답에 필요하지 않음
- API 응답을 하기 위해
HttpServletResponse
에 직접 응답 데이터를 넣음- 매우 불편한 방식
- 특정 컨트롤러에서만 발생하는 예외를 별도로 처리하기 어려움
→ 회원을 처리하는 컨트롤러와 상품을 관리하는 컨트롤러에서 각각 발생한RuntimeException
을 서로 다른 방식으로 처리하려면?
✔️ @ExceptionHandler
- API 예외 처리 문제를 해결하기 위해 스프링이 제공하는 매우 편리한 기능이 바로
ExceptionHandlerExceptionResolver
!- 스프링은
ExceptionHandlerExceptionResolver
을 기본으로 제공
→ExceptionResolver
중에서 우선순위가 가장 높음
- 스프링은
@ExceptionHandler
예외 처리 방법@ExceptionHandler
애노테이션을 선언 → 해당 컨트롤러에서 처리하고 싶은 예외를 지정- 해당 컨트롤러에서 예외가 발생하면 이 메서드가 호출
- 참고 : 지정한 예외와 그 예외의 자식 클래스 모두 잡음
📌 스프링의 우선순위는 항상 자세한 것이 우선권을 가진다.
실행 흐름
- 예제 코드에서의 실행 흐름
- 컨트롤러가 호출한 결과
IllegalArgumentException
예외가 컨트롤러 밖으로 던져짐 - 예외 발생 →
ExceptionResolver
작동. 가장 우선순위가 높은ExceptionHandlerExceptionResolver
가 실행 ExceptionHandlerExceptionResolver
는 해당 컨트롤러에IllegalArgumentException
을 처리할 수 있는@ExceptionHandler
가 있는지 확인illegalExHandler()
실행.@RestController
이므로@ResponseBody
가 적용- HTTP 컨버터 사용 → 응답이 JSON으로 반환
@ResponseStatus(HttpStatus.BAD_REQUEST)
가 지정되어 있으므로 HTTP 상태코드 400으로 응답
🏷 @ControllerAdvice
@ExceptionHandler
를 사용해 예외를 깔끔하게 처리할 수 있게 되었지만, 정상 코드와 예외 처리 코드가 하나의 컨트롤러에 섞여 있음
→@ControllerAdvice
또는@RestControllerAdvice
를 사용해 분리 가능
✔️ ExControllerAdvice
@ControllerAdvice
@ControllerAdvice
는 대상으로 지정한 여러 컨트롤러에@ExceptionHandler
,@InitBinder
기능을 부여해주는 역할@ControllerAdvice
에 대상을 지정하지 않으면 모든 컨트롤러에 적용됨. (글로벌 적용)
@RestControllerAdvice
@ControllerAdvice
와 같고,@ResponseBody
가 추가@Controller
,@RestController
의 차이와 동일
📌 대상 컨트롤러 지정 방법
// Target all Controllers annotated with @RestController @ControllerAdvice(annotations = RestController.class) public class ExampleAdvice1 {} // Target all Controllers within specific packages @ControllerAdvice("org.example.controllers") public class ExampleAdvice2 {} // Target all Controllers assignable to specific classes @ControllerAdvice(assignableTypes = {ControllerInterface.class, AbstractController.class}) public class ExampleAdvice3 {}
🌟 자세한 부분은 스프링 공식 문서 참고
Comments
SPRING 의 다른 글
-
스프링 타입 컨터버 24 Jun 2022
-
API 예외 처리 17 Jun 2022
-
예외 처리와 오류 페이지 12 Jun 2022
-
로그인 처리 - 인터셉터 08 Jun 2022
-
로그인 처리 - 필터 06 Jun 2022
-
로그인 처리 - 쿠키, 세션 31 May 2022
-
Bean Validation 22 May 2022
-
검증 22 May 2022
-
메시지, 국제화 21 May 2022
-
타임리프 - 스프링 통합과 폼 19 May 2022
-
타임리프 - 기본 기능 10 May 2022
-
스프링 MVC 기본 기능 - 웹 페이지 만들기 02 May 2022
-
스프링 MVC 기본 기능 - HTTP 응답 30 Apr 2022
-
스프링 MVC 기본 기능 - HTTP 요청 24 Apr 2022
-
스프링 MVC 기본 기능 - 요청 매핑 19 Apr 2022
-
스프링 MVC 기본 기능 19 Apr 2022
-
스프링 MVC 구조 이해 14 Apr 2022
-
MVC 프레임워크 만들기 - V4, V5 12 Apr 2022
-
MVC 프레임워크 만들기 - V1, V2, V3 09 Apr 2022
-
서블릿, JSP, MVC 패턴 05 Apr 2022
-
서블릿 29 Mar 2022
-
웹 애플리케이션 이해 24 Mar 2022
-
스프링 웹 계층이란? 05 Nov 2021
-
스프링 시큐리티 공식문서 번역 27 Sep 2021
-
스프링 AOP 총정리 : 개념, 프록시 기반 AOP, @AOP 27 Apr 2021
-
SpEL (스프링 Expression Language) 25 Apr 2021
-
데이터 바인딩 추상화 : Converter와 Formatter 21 Apr 2021
-
데이터 바인딩 추상화 : PropertyEditor 12 Apr 2021
-
Validation 추상화 10 Apr 2021
-
Resource 추상화 08 Apr 2021
-
IoC 컨테이너 9부 07 Apr 2021
-
IoC 컨테이너 8부 06 Apr 2021
-
IoC 컨테이너 7부 02 Apr 2021
-
IoC 컨테이너 6부 29 Mar 2021
-
IoC 컨테이너 5부 27 Mar 2021
-
IoC 컨테이너 4부 23 Mar 2021
-
IoC 컨테이너 3부 20 Mar 2021
-
IoC 컨테이너 2부 18 Mar 2021
-
IoC 컨테이너 1부 12 Mar 2021
-
스프링 PSA 07 Jan 2021
-
스프링 @AOP 실습 07 Jan 2021
-
프록시 패턴 06 Jan 2021
-
스프링 AOP 04 Jan 2021
-
의존성 주입(Dependency Injection) 04 Jan 2021
-
스프링 빈(Bean) 02 Jan 2021
-
스프링 IoC 컨테이너 01 Jan 2021
-
스프링 IoC 01 Jan 2021