- 
                            
                            API ์์ธ ์ฒ๋ฆฌ - HandlerExceptionResolver(1)๊ฐ๋ฐ/Spring Boot 2022. 7. 7. 22:55 ์คํ๋ง ๋ถํธ์ ์์ธ ์ฒ๋ฆฌ 
 ์คํ๋ง ๋ถํธ์ ๊ธฐ๋ณธ ์ค์ ์ ์ค๋ฅ ๋ฐ์์ /error ๋ฅผ ์ค๋ฅ ํ์ด์ง๋ก ์์ฒญํ๋ค. BasicErrorController ๋ ์ด ๊ฒฝ๋ก๋ฅผ ๊ธฐ๋ณธ์ผ๋ก ๋ฐ๋๋ค. ( server.error.path ๋ก ์์  ๊ฐ๋ฅ, ๊ธฐ๋ณธ ๊ฒฝ๋ก / error ) ์คํ๋ง ๋ถํธ๋ BasicErrorController ๊ฐ ์ ๊ณตํ๋ ๊ธฐ๋ณธ ์ ๋ณด๋ค์ ํ์ฉํด์ ์ค๋ฅ API๋ฅผ ์์ฑํด์ค๋ค. ๋ค์ ์ต์ ๋ค์ ์ค์ ํ๋ฉด ๋ ์์ธํ ์ค๋ฅ ์ ๋ณด๋ฅผ ์ถ๊ฐํ ์ ์๋ค. server.error.include-binding-errors=always 
 server.error.include-exception=true
 server.error.include-message=always
 server.error.include-stacktrace=always๋ฌผ๋ก ์ค๋ฅ ๋ฉ์์ง๋ ์ด๋ ๊ฒ ๋ง ์ถ๊ฐํ๋ฉด ๋ณด์์ ์ํํ ์ ์๋ค. ๊ฐ๊ฒฐํ ๋ฉ์์ง๋ง ๋ ธ์ถํ๊ณ , ๋ก๊ทธ๋ฅผ ํตํด์ ํ์ธํ์. Html ํ์ด์ง vs API ์ค๋ฅ์คํ๋ง ๋ถํธ๊ฐ ์ ๊ณตํ๋ BasicErrorController ๋ HTML ํ์ด์ง๋ฅผ ์ ๊ณตํ๋ ๊ฒฝ์ฐ์๋ ๋งค์ฐ ํธ๋ฆฌํ๋ค. 4xx, 5xx ๋ฑ๋ฑ ๋ชจ๋ ์ ์ฒ๋ฆฌํด์ค๋ค. ๊ทธ๋ฐ๋ฐ API ์ค๋ฅ ์ฒ๋ฆฌ๋ ๋ค๋ฅธ ์ฐจ์์ ์ด์ผ๊ธฐ์ด๋ค. API ๋ง๋ค, ๊ฐ๊ฐ์ ์ปจํธ๋กค๋ฌ๋ ์์ธ๋ง๋ค ์๋ก ๋ค๋ฅธ ์๋ต ๊ฒฐ๊ณผ๋ฅผ ์ถ๋ ฅํด์ผ ํ ์๋ ์๋ค. ์๋ฅผ ๋ค์ด์ ํ์๊ณผ ๊ด๋ จ๋ API์์ ์์ธ๊ฐ ๋ฐ์ํ ๋ ์๋ต๊ณผ, ์ํ๊ณผ ๊ด๋ จ๋ API์์ ๋ฐ์ํ๋ ์์ธ์ ๋ฐ๋ผ ๊ทธ ๊ฒฐ๊ณผ๊ฐ ๋ฌ๋ผ์ง ์ ์๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก ๋งค์ฐ ์ธ๋ฐํ๊ณ ๋ณต์กํ๋ค. (๋ฐ๋ผ์ ์ด ๋ฐฉ๋ฒ์ HTML ํ๋ฉด์ ์ฒ๋ฆฌํ ๋ ์ฌ์ฉํ๊ณ , ๊ฒฐ๋ก ์ ์ผ๋ก API๋ ์ค๋ฅ ์ฒ๋ฆฌ๋ ๋ค์ ๊ธ์์ ์ค๋ช ํ @ExceptionHandler ๋ฅผ ์ฌ์ฉํ์.) HandlerExceptionResolver์์ธ๊ฐ ๋ฐ์ํด์ ์๋ธ๋ฆฟ์ ๋์ด WAS๊น์ง ์์ธ๊ฐ ์ ๋ฌ๋๋ฉด HTTP ์ํ์ฝ๋๊ฐ 500์ผ๋ก ์ฒ๋ฆฌ๋๋ค. ๊ทธ๋ฐ๋ฐ ๋ฐ์ํ๋ ์์ธ์ ๋ฐ๋ผ์ 400, 404 ๋ฑ๋ฑ ๋ค๋ฅธ ์ํ์ฝ๋๋ ์ฒ๋ฆฌํด์ผ ํ ๊ฒฝ์ฐ๋ ์๊ณ , ์ค๋ฅ ๋ฉ์์ง๋ ํ์๋ฑ์ API๋ง๋ค ๋ค๋ฅด๊ฒ ์ฒ๋ฆฌํ๊ณ ์ถ์ ๊ฒฝ์ฐ๊ฐ ์๋ค. ์คํ๋ง MVC๋ ์ปจํธ๋กค๋ฌ(ํธ๋ค๋ฌ) ๋ฐ์ผ๋ก ์์ธ๊ฐ ๋์ ธ์ง ๊ฒฝ์ฐ ์์ธ๋ฅผ ํด๊ฒฐํ๊ณ , ๋์์ ์๋ก ์ ์ํ ์ ์๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํ๋ค. ์ปจํธ๋กค๋ฌ ๋ฐ์ผ๋ก ๋์ ธ์ง ์์ธ๋ฅผ ํด๊ฒฐํ๊ณ , ๋์ ๋ฐฉ์์ ๋ณ๊ฒฝํ๊ณ ์ถ์ผ๋ฉด HandlerExceptionResolver ๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค. ์ค์ฌ์ ExceptionResolver ๋ผ ํ๋ค.  ์ถ์ฒ : ๊น์ํ - ์คํ๋ง MVC ์์ ๊ทธ๋ฆผ ์ฒ๋ผ, ExceptionResolver๋ฅผ ์ ์ฉํ๋ฉด, ์ด ๋ฆฌ์กธ๋ฒ๋ฅผ ํธ์ถํ๊ณ ์์ธ ํด๊ฒฐ ์๋๋ฅผ ํจ์ผ๋ก์จ ์ดํ ์ ์์ ์ผ๋ก model์ ํธ์ถํ ์ ์๊ฒ ๋๋ค. (๋ค๋ง, ExceptionResolver๋ก ์์ธ๋ฅผ ํด๊ฒฐํด๋ postHandle()์ ํธ์ถ๋์ง ์๋๋ค.) ์ฝ๋๋ก ํ์ธํด๋ณด์. ์ด๋ฐ์์ผ๋ก ์์ฑํด์ฃผ๋ฉด ๋๋ค. @Slf4j public class MyHandlerExceptionResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { log.info("call resolver", ex); try { if (ex instanceof IllegalArgumentException) { log.info("IllegalArgumentException resolver to 400"); response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.getMessage()); return new ModelAndView(); } } catch (IOException e) { log.error("resolver ex", e); } return null; } }ExceptionResolver ๊ฐ ModelAndView ๋ฅผ ๋ฐํํ๋ ์ด์ ๋ ๋ง์น try, catch๋ฅผ ํ๋ฏ์ด, Exception ์ ์ฒ๋ฆฌํด์ ์ ์ ํ๋ฆ ์ฒ๋ผ ๋ณ๊ฒฝํ๋ ๊ฒ์ด ๋ชฉ์ ์ด๋ค. ์ด๋ฆ ๊ทธ๋๋ก Exception ์ Resolver(ํด๊ฒฐ)ํ๋ ๊ฒ์ด ๋ชฉ์ ์ด๋ค. ์ฌ๊ธฐ์๋ IllegalArgumentException ์ด ๋ฐ์ํ๋ฉด response.sendError(400) ๋ฅผ ํธ์ถํด์ HTTP ์ํ ์ฝ๋๋ฅผ 400์ผ๋ก ์ง์ ํ๊ณ , ๋น ModelAndView ๋ฅผ ๋ฐํํ๋ค. HandlerExceptionResolver ์ ๋ฐํ ๊ฐ์ ๋ฐ๋ฅธ DispatcherServlet ์ ๋์ ๋ฐฉ์์ ๋ค์๊ณผ ๊ฐ๋ค. ๋น ModelAndView 
 new ModelAndView() ์ฒ๋ผ ๋น ModelAndView ๋ฅผ ๋ฐํํ๋ฉด ๋ทฐ๋ฅผ ๋ ๋๋ง ํ์ง ์๊ณ , ์ ์ ํ๋ฆ์ผ๋ก ์๋ธ๋ฆฟ์ด ๋ฆฌํด๋๋ค.
 ModelAndView ์ง์ 
 ModelAndView ์ View , Model ๋ฑ์ ์ ๋ณด๋ฅผ ์ง์ ํด์ ๋ฐํํ๋ฉด ๋ทฐ๋ฅผ ๋ ๋๋ง ํ๋ค.
 null
 null ์ ๋ฐํํ๋ฉด, ๋ค์ ExceptionResolver ๋ฅผ ์ฐพ์์ ์คํํ๋ค. ๋ง์ฝ ์ฒ๋ฆฌํ ์ ์๋ ExceptionResolver ๊ฐ ์์ผ๋ฉด ์์ธ ์ฒ๋ฆฌ๊ฐ ์๋๊ณ , ๊ธฐ์กด์ ๋ฐ์ํ ์์ธ๋ฅผ ์๋ธ๋ฆฟ ๋ฐ์ผ๋ก ๋์ง๋ค.์ถ๊ฐ) ์์ธ๋ฅผ ์ค๋ฅ ์ฝ๋๋ฅผ ๋ฃ์ด response.sendError(xxx) ํธ์ถ๋ก ๋ณ๊ฒฝํด์ ์๋ธ๋ฆฟ์์ ์ํ ์ฝ๋์ ๋ฐ๋ฅธ ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํ๋๋ก ์์ํ ์ ์๋ค. ์ดํ WAS๋ ์๋ธ๋ฆฟ ์ค๋ฅํ์ด์ง๋ฅผ ์ฐพ์์ ๋ด๋ถ ํธ์ถํ ๊ฒ์ด๋ค. ์๋ฅผ ๋ค์ด์ ์คํ๋ง๋ถํธ๊ฐ ๊ธฐ๋ณธ์ผ๋ก ์ค์ ํ /error ๊ฐ ํธ์ถ๋๋ค. ๋ํ ModelAndView ์ ๊ฐ์ ์ฑ์์ ์์ธ์ ๋ฐ๋ฅธ ์๋ก์ด ์ค๋ฅ ํ๋ฉด ๋ทฐ ๋ ๋๋ง ํด์ ๊ณ ๊ฐ์๊ฒ ์ ๊ณตํ ์๋ ์๋ค. response.getWriter().println("hello"); ์ฒ๋ผ HTTP ์๋ต ๋ฐ๋์ ์ง์  ๋ฐ์ดํฐ๋ฅผ ๋ฃ์ด์ฃผ๋ ๊ฒ๋ ๊ฐ๋ฅํ๋ค. ์ฌ๊ธฐ์ JSON ์ผ๋ก ์๋ตํ๋ฉด API ์๋ต ์ฒ๋ฆฌ๋ฅผ ํ ์ ์๋ค. ๊ทธ๋ฆฌ๊ณ ์์ง๋ง๊ณ WebConfig์ ๋ฑ๋ก์ ํด์ฃผ์. ( configureHandlerExceptionResolvers(..) ๋ฅผ ์ฌ์ฉํ๋ฉด ์คํ๋ง์ด ๊ธฐ๋ณธ์ผ๋ก ๋ฑ๋กํ๋ ExceptionResolver ๊ฐ ์ ๊ฑฐ๋๋ฏ๋ก ์ฃผ์, extendHandlerExceptionResolvers ๋ฅผ ์ฌ์ฉํ์.) @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) { resolvers.add(new MyHandlerExceptionResolver()); } }์์ธ๊ฐ ๋ฐ์ํ๋ฉด WAS๊น์ง ์์ธ๊ฐ ๋์ ธ์ง๊ณ , WAS์์ ์ค๋ฅ ํ์ด์ง ์ ๋ณด๋ฅผ ์ฐพ์์ ๋ค์ /error ๋ฅผ ํธ์ถํ๋ ๊ณผ์ ์ ์๊ฐํด๋ณด๋ฉด ๋๋ฌด ๋ณต์กํ๋ค. ExceptionResolver ๋ฅผ ํ์ฉํ๋ฉด ์์ธ๊ฐ ๋ฐ์ํ์ ๋ ์ด๋ฐ ๋ณต์กํ ๊ณผ์  ์์ด ์ฌ๊ธฐ์์ ๋ฌธ์ ๋ฅผ ๊น๋ํ๊ฒ ํด๊ฒฐํ ์ ์๋ค. ExceptionResolver ๋ฅผ ์ฌ์ฉํ๋ฉด ์ปจํธ๋กค๋ฌ์์ ์์ธ๊ฐ ๋ฐ์ํด๋ ExceptionResolver ์์ ์์ธ๋ฅผ ์ฒ๋ฆฌํด๋ฒ๋ฆฐ๋ค. ๋ฐ๋ผ์ ์์ธ๊ฐ ๋ฐ์ํด๋ ์๋ธ๋ฆฟ ์ปจํ ์ด๋๊น์ง ์์ธ๊ฐ ์ ๋ฌ๋์ง ์๊ณ , ์คํ๋ง MVC์์ ์์ธ ์ฒ๋ฆฌ๋ ๋์ด ๋๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก WAS ์ ์ฅ์์๋ ์ ์ ์ฒ๋ฆฌ๊ฐ ๋ ๊ฒ์ด๋ค. ์ด๋ ๊ฒ ์์ธ๋ฅผ ์ด๊ณณ์์ ๋ชจ๋ ์ฒ๋ฆฌํ ์ ์๋ค๋ ๊ฒ์ด ํต์ฌ์ด๋ค. ์๋ธ๋ฆฟ ์ปจํ ์ด๋๊น์ง ์์ธ๊ฐ ์ฌ๋ผ๊ฐ๋ฉด ๋ณต์กํ๊ณ ์ง์ ๋ถํ๊ฒ ์ถ๊ฐ ํ๋ก์ธ์ค๊ฐ ์คํ๋๋ค. ๋ฐ๋ฉด์ ExceptionResolver ๋ฅผ ์ฌ์ฉํ๋ฉด ์์ธ์ฒ๋ฆฌ๊ฐ ์๋นํ ๊น๋ํด์ง๋ค. ๊ทธ๋ฐ๋ฐ ์ง์  ExceptionResolver ๋ฅผ ๊ตฌํํ๋ ค๊ณ ํ๋ ์๋นํ ๋ณต์กํ๋ค. ๋ค์ ๊ธ ๋ถํฐ๋ ์คํ๋ง์ด ์ ๊ณตํ๋ ExceptionResolver ๋ค์ ์์๋ณด์. '๊ฐ๋ฐ > Spring Boot' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธAPI ์์ธ ์ฒ๋ฆฌ - @ControllerAdvice (0) 2022.07.08 API ์์ธ ์ฒ๋ฆฌ - HandlerExceptionResolver(2) : ResponseStatusExceptionResolver, DefaultHandlerExceptionResolver, ExceptionHandlerExceptionResolver (0) 2022.07.08 Http Message Converter ์ด์ผ๊ธฐ(2) (0) 2022.07.07 HTTP Message Converter ์ด์ผ๊ธฐ(1) (0) 2022.07.07 HTTP API ์๋ต ์ ๋ฆฌ (0) 2022.07.07