일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 스프링 mvc1 - 스프링 mvc
- @Aspect
- 스프링 db1 - 스프링과 문제 해결
- 자바의 정석 기초편 ch2
- 스프링 mvc2 - 로그인 처리
- 2024 정보처리기사 수제비 실기
- 자바의 정석 기초편 ch4
- 타임리프 - 기본기능
- 자바의 정석 기초편 ch8
- 스프링 mvc2 - 검증
- 자바의 정석 기초편 ch3
- 자바의 정석 기초편 ch11
- 자바의 정석 기초편 ch12
- 스프링 고급 - 스프링 aop
- 스프링 mvc2 - 타임리프
- 자바의 정석 기초편 ch13
- jpa 활용2 - api 개발 고급
- 2024 정보처리기사 시나공 필기
- jpa - 객체지향 쿼리 언어
- 스프링 입문(무료)
- 스프링 db2 - 데이터 접근 기술
- 자바의 정석 기초편 ch9
- 자바의 정석 기초편 ch6
- 스프링 mvc1 - 서블릿
- 자바의 정석 기초편 ch1
- 자바의 정석 기초편 ch5
- 자바의 정석 기초편 ch14
- 코드로 시작하는 자바 첫걸음
- 게시글 목록 api
- 자바의 정석 기초편 ch7
- Today
- Total
나구리의 개발공부기록
예외 처리와 오류페이지 - 프로젝트 생성, 서블릿 예외처리 (시작/오류 화면 제공/오류 페이지 작동 원리/필터/인터셉터), 스프링부트 - 오류페이지 본문
예외 처리와 오류페이지 - 프로젝트 생성, 서블릿 예외처리 (시작/오류 화면 제공/오류 페이지 작동 원리/필터/인터셉터), 스프링부트 - 오류페이지
소소한나구리 2024. 9. 6. 20:20 출처 : 인프런 - 스프링 MVC 2편 - 백엔드 웹 개발 핵심 기술 (유료) / 김영한님
유료 강의이므로 정리에 초점을 두고 코드는 일부만 인용
1. 예외 처리와 오류페이지 - 프로젝트 생성
- Project - Gradle
- Language - Java(사용하는 버전 체크)
- Group - hello
- Artifact - exception
- Packaging - Jar
- Dependencies - Spring Web, Lombok, Thymeleaf, Validation
2. 서블릿 예외처리 - 시작
1) 순수 서블릿 컨테이너의 예외 처리
- 서블릿은 2가지의 방식으로 예외를 처리함
- Exception(예외)
- response.sendError(Http 상태 코드, 오류 메시지)
2) Exception
(1) 자바 직접 실행
- 자바의 main 메서드를 실행하는 경우 main이라는 쓰레드가 실행 되는데, 실행 도중 예외를 잡지 못하고 처음 실행한 main()메서들을 넘어가서 예외가 던져지면, 예외 정보를 남기고 해당 쓰레드는 종료 됨
(2) 웹 애플리케이션
- 사용자 요청별로 별도의 쓰레드가 할당되고 서블릿 컨테이너 안에서 실행됨
- 애플리케이션에서 에외가 발생되어 try - catch로 예외를 잡으면 문제가 안되지만 예외를 잡지 못하면 톰캣 같은 WAS까지 쭉 예외가 전달됨
- WAS(여기까지 전파 됨) <- 필터 <- 서블릿 <- 인터셉터 <- 컨트롤러(예외 발생)
3) 서블릿 컨테이너의 예외 페이지
- 스프링 부트가 제공하는 기본 예외 페이지 기능을 꺼두기
- application.properties에 server.error.whitelabel.enabled=false를 입력
(1) ServletExController
- 그냥 예외를 던지는 컨트롤러
@Slf4j
@Controller
public class ServletExController {
@GetMapping("/error-ex")
public void errorEx() {
throw new RuntimeException("예외 발생");
}
}
- 컨트롤러 작성 후 서버를 시작하여 /error-ex 접속 하면 500에러가, 아무 사이트나 접속하면 404 에러가 아래의 이미지 처럼 뜸
3) response.sendError(HTTP 상태코드, 오류페이지)
- HttpServletResponse가 제공하는 sendError 메서드를 사용하면 상태코드를 선택하고, 에러 메세지를 입력할 수도 있음
- 당장 예외가 발생하는것은 아니지만 서블릿 컨테이너에게 오류가 발생했다는 점을 전달할 수 있음
(1) ServletExController - error404(), error500() 추가
- 에러코드와 메세지, 에러코드만 전송하는 메서드를 생성
@GetMapping("/error-404")
public void error404(HttpServletResponse response) throws IOException {
response.sendError(404, "404 오류 발생!");
}
@GetMapping("/error-500")
public void error500(HttpServletResponse response) throws IOException {
response.sendError(500);
}
- 재실행 후 /error-404, /error-500에 접속하면 response.sendError로 지정한 에러 메세지가 출력되는 것을 확인할 수 있음
(2) sendError 흐름
- WAS(sendError 호출 기록 확인) <- 필터 <- 서블릿 <- 인터셉터 <- 컨트롤러(response.sendError())
- response.sendError()를 호출하면 response내부에는 오류가 발생했는 상태를 저장해두고 서블릿 컨테이너는 고객에게 응답 전에 response에 sendError()가 호출 되어있는지 확인
- 호출 되었다면 오류 코드에 맞추어 기본 오류 페이지를 보여줌
3. 서블릿 예외 처리 - 오류 화면 제공
- 서블릿 컨테이너가 제공하는 기본 예외 처리 화면은 고객 친화적이지 않으므로 서블릿이 제공하는 오류 화면 기능을 사용하면 사용자에게 친절한 오류 처리 화면을 준비해서 고객에게 보여줄 수 있음
- 과거에는 web.xml이라는 파일에 아래와 같이 작성하여 오류 화면을 등록했음
<error-page>
<error-code>500</error-code>
<location>/error-page/500.html</location>
</error-page>
<error-page>
<exception-type>java.lang.RuntimeException</exception-type>
<location>/error-page/500.html</location>
</error-page>
</web-app>
- 지금은 스프링 부트를 통해서 서블릿 컨테이너를 실행하기 때문에 스프링 부트가 제공하는 기능을 사용해서 서브릿 오류 페이지를 등록하면 됨
1) 서블릿 오류 페이지 등록
- 404, 500, RuntimeException을 경로를 설정하여 ErrorPage를 생성하고 addErrorPages()로 등록
- 오류페이지는 예외를 다룰 때 해당 예외와 그 자식 타입의 오류를 함께 처리하게 됨
package hello.exception;
@Component
public class WebServerCustomizer implements WebServerFactoryCustomizer<ConfigurableWebServerFactory> {
@Override
public void customize(ConfigurableWebServerFactory factory) {
// Http 상태 코드 에러
ErrorPage errorPage404 = new ErrorPage(HttpStatus.NOT_FOUND, "/error-page/404");
ErrorPage errorPage500 = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error-page/500");
// RuntimeException 및 그 자식타입의 예외
ErrorPage errorPageEx = new ErrorPage(RuntimeException.class, "/error-page/500");
// 등록
factory.addErrorPages(errorPage404, errorPage500, errorPageEx);
}
}
2) 컨트롤러 생성
- 등록한 오류페이지를 보여주기 위한 컨트롤러
- 에러가 발생하면 등록한 에러 페이지의 경로로 보내서 에러페이지를 보여줌
package hello.exception.servlet;
@Slf4j
@Controller
public class ErrorPageController {
@RequestMapping("/error-page/404")
public String errorPage404(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
log.info("errorPage 404");
return "error-page/404";
}
@RequestMapping("/error-page/500")
public String errorPage500(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
log.info("errorPage 404");
return "error-page/500";
}
}
3) 오류 처리 View 생성
- ~/templates/error-page/에 404.html, 500html을 생성
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
</head>
<div class="container" style="max-width: 600px">
<div class="py-5 text-center">
<h2>404 오류 화면</h2></div>
<div>
<p>오류 화면 입니다.</p>
</div>
<hr class="my-4">
</div> <!-- /container -->
</body>
</html>
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
</head>
<div class="container" style="max-width: 600px">
<div class="py-5 text-center">
<h2>500 오류 화면</h2></div>
<div>
<p>오류 화면 입니다.</p>
</div>
<hr class="my-4">
</div> <!-- /container -->
</body>
</html>
4) 실행 결과
- error-ex, error-404, error-500으로 접속하면 등록한 에러페이지가 나옴
- 등록된 에러가 발생하면 WAS가 예외가 터졌다는것을 알고 에러페이지를 보여줌
4. 서블릿 예외 처리 - 오류 페이지 작동 원리
1) 예외 발생과 오류 페이지 요청 흐름
- 서블릿은 예외가 발생해서 서블릿 밖으로 전달되거나 response.sendError()가 호출되면 설정된 오류페이지를 찾음
- WAS는 해당 예외를 처리하는 오류 페이지 정보를 확인하고 지정되어있는 오류페이지로 다시 재요청함
(1) 구조: WAS - 필터 - 서블릿 - 인터셉터 - 컨트롤러
- WAS(여기까지 전파) <- 필터 <- 서블릿 <- 인터셉터 <-컨트롤러(예외발생)
- WAS(예외를 확인하고 지정된 경로로 다시 재요청) -> 필터 -> 서블릿 -> 인터셉터 -> 컨트롤러(지정된 경로 호출) -> View
(2) 중요한점
- 웹 브라우저(클라이언트)는 서버 내부에서 이런 일이 일어나는지 전혀 모르고 오직 서버 내부에서 오류 페이지를 찾기 위해 추가적인 호출을 함
- 한마디로 재요청되는 경로에 있는 필터, 서블릿, 인터셉트, 컨트롤러가 모두 다시 호출 됨
2) 오류 정보 추가
- WAS는 오류 페이지를 다시 요청만 하는 것이 아니라 오류 정보를 request의 attribute에 추가해서 넘기기 때문에 필요하면 오류 페이지에서 전달된 오류 정보를 사용할 수 있음
(1) ErrorPageController - 오류 출력을 위한 수정
- RequestDispatcher에 가면 오류 정보가 있어서 필요한 정보를 가져와서 출력해볼 수 있음
- 아래 컨트롤러를 적용하고 실행해서 에러가 발생하는 경로로 이동하면 에러 정보들을 출력할 수 있음
package hello.exception.servlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Slf4j
@Controller
public class ErrorPageController {
/* RequestDispatcher: 오류 정보가 상수로 정의 되어 있음 */
String ERROR_EXCEPTION = "jakarta.servlet.error.exception"; // 예외
String ERROR_EXCEPTION_TYPE = "jakarta.servlet.error.exception_type"; // 예외타입
String ERROR_MESSAGE = "jakarta.servlet.error.message"; // 오류 메세지
String ERROR_REQUEST_URI = "jakarta.servlet.error.request_uri"; // 클라이언트 요청 URI
String ERROR_SERVLET_NAME = "jakarta.servlet.error.servlet_name"; // 오류가 발생한 서블릿 이름
String ERROR_STATUS_CODE = "jakarta.servlet.error.status_code"; // HTTP 상태 코드
// 주요 정보만 가져와서 출력
private void printErrorInfo(HttpServletRequest request) {
log.info("ERROR_EXCEPTION {}",request.getAttribute(ERROR_EXCEPTION));
log.info("ERROR_EXCEPTION_TYPE {}",request.getAttribute(ERROR_EXCEPTION_TYPE));
log.info("ERROR_MESSAGE {}",request.getAttribute(ERROR_MESSAGE));
log.info("ERROR_REQUEST_URI {}",request.getAttribute(ERROR_REQUEST_URI));
log.info("ERROR_SERVLET_NAME {}",request.getAttribute(ERROR_SERVLET_NAME));
log.info("ERROR_STATUS_CODE {}",request.getAttribute(ERROR_STATUS_CODE));
log.info("dispatchType={}", request.getDispatcherType());
}
@RequestMapping("/error-page/404")
public String errorPage404(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
log.info("error-page/404");
printErrorInfo(httpServletRequest);
return "error-page/404";
}
@RequestMapping("/error-page/500")
public String errorPage500(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
log.info("error-page/500");
printErrorInfo(httpServletRequest);
return "error-page/500";
}
}
5. 서블릿 예외 처리 - 필터
- 오류가 발생하면 오류 페이지를 출력하기 위해 WAS 내부에서 다시한번 호출이 발생 되는데 이때 필터, 서블릿, 인터셉터도 모두 다시 호출되어 중복 호출이 발생 됨
- 로그인 인증 체크 같은 경우 한번 필터나 인터셉터에서 체크를 완료했는데 오류 페이지를 출력한다고 다시 체크하는 것은 비효율 적이고 중복 호출 되면 안되는 필터나 인터셉터도 존재 할 수 있기에 방지를 해야함
- 클라이언트로부터 발생한 정상 요청인지, 아니면 오류 페이지를 출력하기 위한 내부 요청인지 구분할 수 있어야 하는데 서블릿이 제공하는 DispatcherType이라는 정보로 해결할 수 있음
1) DispatcherType
- 고객이 처음 요청하면 REQUEST로 오류 정보면 ERROR로 dispatcherType을 반환함
public enum DispatcherType {
FORWARD, // MVC에서 배웠던 서블릿에서 다른 서블릿이나 JSP를 호출할 때
INCLUDE, // 서블릿에서 다른 서블릿이나 JSP의 결과를 포함할 때
REQUEST, // 클라이언트 요청
ASYNC, // 서블릿 비동기 호출
ERROR // 오류 요청
}
2) 필터와 DispatcherType
(1) LogFilter - DispatcherType 로그 추가
- Filter 수업때 배웠던 코드와 동일하므로 추가 부분만 작성
package hello.exception.filter;
@Slf4j
public class LogFilter implements Filter {
// ... 기존 코드 동일
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
// ... 기존 코드 동일
// 출력에 getDispatcherType()으로 디스패처타입 정보를 출력
try {
log.info("REQUEST [{}][{}][{}]", uuid, httpRequest.getDispatcherType(), requestURI);
filterChain.doFilter(servletRequest, servletResponse);
} catch (Exception e) {
throw e;
} finally {
log.info("RESPONSE [{}][{}][{}]", uuid, httpRequest.getDispatcherType(), requestURI);
}
}
// ... 기존 코드 동일
}
(2) WebConfig - 필터 등록
- Filter 수업때 배웠던 코드와 동일하므로 추가 부분만 작성
- 필터 설정에 filterRegistrationBean.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ERROR); 등록
- DispatcherType이 REQUEST, ERROR일때 해당 필터를 적용하도록 설정
package hello.exception;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Bean
public FilterRegistrationBean logFilter() {
// ... 기존코드 동일
// 해당 필터는 DispatcherType이 REQUEST, ERROR 일때 사용이 된다는 뜻
filterRegistrationBean.setDispatcherTypes(DispatcherType.REQUEST,DispatcherType.ERROR);
return filterRegistrationBean;
}
}
(3) 로그 확인
- 로그를 확인해보면 필터가 두번 동작하는 것을 확인할 수 있음
- setDispatcherTypes()로 Dispatcher타입별로 필터를 동작되게 만들어서 중복 요청을 막을 수 있음
- 해당 값에 아무것도 넣지 않으면 기본값으로 DispatcherType.REQUEST이므로 특별히 오류 페이지 경로도 필터를 적용할 것이 아니면 기본값을 그대로 사용하면 됨
- 오류 페이지 요청 전용 필터를 적용하고 싶으면 DispatcherType.ERROR만 지정하면 됨
6. 서블릿 예외 처리 - 인터셉터
1) 인터셉터 중복 호출 제거
(1) LogInterceptor - DispatcherType 로그 추가
- 인터셉터 수업때 배웠던 코드와 동일하므로 추가 부분만 작성
package hello.exception.interceptor;
@Slf4j
public class LogInterceptor implements HandlerInterceptor {
// ... 기존 코드 동일
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
// ... 기존 코드 동일
log.info("REQUEST [{}][{}][{}][{}]", uuid, request.getDispatcherType(), requestURI, handler);
return true;
}
// ... 기존 코드 동일
}
(2) WebConfig 등록
- 인터셉터는 등록 시 설정에 DispatcherType을 설정하는 것이 아닌 exludePathPatterns에 오류 페이지 URL을 허용하면 중복 호출을 막을 수 있음
- 만약 오류페이지 경로를 등록하지 않으면 중복 호출되고 에러페이지를 호출하는 정상 호출로 간주되어 postHandler까지 호출됨
package hello.exception;
@Configuration
public class WebConfig implements WebMvcConfigurer {
// 인터셉터는 설정에 DispatcherType 설정을 할 수 없어서 excludePathPatterns 에 오류페이지 URL을 등록하면 됨
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogInterceptor())
.order(1).addPathPatterns("/**")
// "/error-page/**" 로 오류페이지 하위 경로의 모든 파일을 허용
.excludePathPatterns("/css/**", "/*.ico", "/error", "/error-page/**");
}
}
2) 전체 흐름 정리
(1) 정상 요청 - /hello
- WAS(/hello, dispatchType=REQUEST) -> 필터 -> 서블릿 -> 인터셉터 -> 컨트롤러 -> View
(2) 오류 요청 - /error-ex
- 필터는 DispatchType 으로 중복 호출 제거: dispatchType=REQUEST
- 인터셉터는 경로 정보로 중복 호출 제거: excludePathPatterns("/error-page/**")
- WAS(/error-ex, dispatchType=REQUEST) -> 필터 -> 서블릿 -> 인터셉터 -> 컨트롤러
- WAS(여기까지 전파) <- 필터 <- 서블릿 <- 인터셉터 <- 컨트롤러(예외발생)
- WAS 오류 페이지 확인
- WAS(/error-page/500, dispatchType=ERROR) -> 필터(x) -> 서블릿 -> 인터셉터(x) ->
컨트롤러(/error-page/500) -> View
7. 스프링부트 - 오류페이지
- 지금까지 예외 처리 페이지를 만들기 위해 WebServerCustomizer를 만들고 ErrorPage를 추가하고 ErrorPageController를 만드는 번거롭고 복잡한 과정을 거쳤음
- 스프링 부트는 이런 과정을 모두 기본으로 자동 제공함
1) 스프링 부트가 기본으로 제공
(1) ErrorPage 자동 등록
- /error라는 경로로 기본 오류 페이지를 설정하여 추가로 설정하지 않는 오류들은 디폴트 경로인 /error로 이동하게 됨
- 상태코드와 예외를 설정하지 않으면 기본 오류 페이지로 사용됨, new ErrorPage("/error")
- 서블릿 밖으로 예외가 발생하거나 response.sendError(...)가 호출되면 별도로 지정하지 않은 모든 오류는 /error를 호출하게됨
- ErrorMvcAutoConfiguration이라는 클래스가 오류 페이지를 자동으로 등록하는 역할을 함
(2) BasicErrorController 자동 등록
- ErrorPage에서 등록한 /error를 매핑해서 처리하는 컨트롤러를 자동으로 등록함
** 실습 주의
- 스프링 부트가 제공하는 기본 오류 메커니즘을 사용하기 위해 만들어 두었던 WebServerCustomizer의 @Component를 주석 처리하여 빈 등록을 제거
2) 개발자는 오류 페이지만 등록
- BasicErrorController는 기본적인 로직이 개발 되어있어서 제공하는 룰과 우선순위에 따라서 오류 페이지 화면만 등록하면 됨
- 정적 오류 화면이면 static, 동적 오류 화면이면 뷰 템플릿을 활용해서 경로에 오류 페이지 파일을 넣어두면 됨
- 5xx.html, 4xx.html 이렇게 파일이름을 작성하여 경로에 넣어놓으면 500번대, 400번대의 에러를 모두 출력하는 에러페이지가 됨
- 404.html ,500.html처럼 에러코드를 정확하게 파일을 작성하면 해당 에러가 발생했을때 동일한 이름의 파일을 출력하게 됨
(1) 뷰 선택 우선순위
- 뷰 템플릿이 정적 리소스보다 우선순위가 높음
- 404, 500 처럼 구체적인것이 5xx처럼 덜 구체적인 것보다 우선순위가 높음
우선순위 | 구분 | 경로 |
1 | 뷰 템플릿 | resources/templates/error/500.html |
2 | resources/templates/error/5xx.html | |
3 | 정적 리소스(static, public) | resources/static/error/400.html |
4 | resources/static/error/404.html | |
5 | resources/static/error/4xx.html | |
6 | 적용 대상이 없을 때 - 뷰이름 (error) | resources/templates/error.html |
(2) 테스트
- 테스트 페이지와 동작하는 컨트롤러를 생성하여 테스트 해보면 아래와같이 우선순위에 따라 동작하는 것을 확인할 수 있음
3) BasicErrorController가 제공하는 기본 정보들
- BasicErrorController는 다음 정보를 model에 담아서 뷰에 전달하므로 동적으로 에러페이지를 구성할때 이 값을 활용해서 출력할 수 있음
- 시간, 상태, 에러 정보, 예외 정보, 클라이언 요청 경로 등등
* timestamp: Fri Sep 06 19:57:44 KST 2024
* status: 400
* error: Bad Request
* exception: org.springframework.validation.BindException * trace: 예외 trace
* message: Validation failed for object='data'. Error count: 1
* errors: Errors(BindingResult)
* path: 클라이언트 요청 경로 (`/hello`)
(1) 오류 정보를 추가한 500.html 템플릿
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
</head>
<div class="container" style="max-width: 600px">
<div class="py-5 text-center">
<h2>500 오류 화면 - 스프링 부트가 제공함</h2></div>
<div>
<p>500 템플릿.</p>
</div>
<ul>
<li>오류 정보</li>
<ul>
<li th:text="|timestamp: ${timestamp}|"></li>
<li th:text="|path: ${path}|"></li>
<li th:text="|status: ${status}|"></li>
<li th:text="|message: ${message}|"></li>
<li th:text="|error: ${error}|"></li>
<li th:text="|exception: ${exception}|"></li>
<li th:text="|errors: ${errors}|"></li>
<li th:text="|trace: ${trace}|"></li>
</ul>
</li>
</ul>
<hr class="my-4">
</div> <!-- /container -->
</body>
</html>
- 대부분 정보는 출력되지만 일부 정보는 출력되지 않았음 - 기본값은 일부로 일부 정보가 막혀있음
- 오류 관련 내부 정보들을 고객에게 노출하는것은 좋지 않음
- 고객은 해당 정보를 읽어도 혼란만 더해지고 해커에게 중요 정보를 노출하는 보안상의 문제가 될 수 있어서 노출하지 않아야 함
- application.properties에서 설정을 조정하여 오류정보를 model 포함할지 여부를 선택할 수 있음
(2) 오류정보 출력 기본값
- server.error.include-exception=false : exception 포함 여부(true , false)
- server.error.include-message=never : message 포함 여부
- server.error.include-stacktrace=never : trace 포함 여부
- server.error.include-binding-errors=never : errors 포함 여부
(3) 오류정보 모두 출력
- 아래처럼 설정하면 null 값이였던 정보가 모두 출력됨
server.error.include-exception=true
server.error.include-message=always
server.error.include-stacktrace=always
server.error.include-binding-errors=always
특정 파라미터가 있을 때만 출력
server.error.include-message=on_param
server.error.include-stacktrace=on_param
server.error.include-binding-errors=on_param
이렇게 파라미터만 있으면 정보가 출력됨
http://localhost:8080/error-ex?message=?stacktrace=
(4) 스프링 부트 오류 관련 옵션
- server.error.whitelabel.enabled=true : 오류 처리 화면을 못 찾을 시, 스프링 whitelabel 오류 페이지 적용(프로젝트 처음 만들었을때 실행하면 나오는 화면)
- server.error.path=/error: 오류 페이지 경로, 스프링이 자동 등록하는 서블릿 글로벌 오류 페이지 경로와 BasicErrorConroller 오류 컨트롤러 경로에 함께 사용됨 - 보통 기본값을 사용해서 건들일이 거의없음
(5) 확장 포인트
- 에러 공통 처리 컨트롤러의 기능을 변경하고 싶으면 ErrorController 인터페이스를 상속받아서 구현하거나 BasicErrorController 상속 받아서 기능을 추가하면 됨
- protected 붙어있는 메서드들을 등록하면 되는데 크게 등록할 일이 많이 없어 사용할 일이 있으면 검색
(6) 정리
- 개발 서버라면 몰라도 실무에서는 이런 에러정보들을 절대 노출하면 안됨 - 보안 위험
- 이쁜 오류 화면과 고객이 이해할 수 있는 간단한 오류 메시지를 보여주고 오류 정보는 서버에 로그로 남겨서 로그로 확인해야함
- 스프링 부트가 기본으로 제공하는 오류 페이지를 활용하면 오류 페이지와 관련된 대부분의 문제는 쉽게 해결할 수 있음