본문으로 바로가기

[스프링부트 (12)]   SpringBoot 에러 페이지 설정(Custom Error Page)

안녕하세요. 갓대희 입니다. 이번 포스팅은 [ Spring Boot Custom Error Page 입니다. : ) 

 

 

0. 에러 페이지를 만들기 앞서

개발하면서 기본적으로 tomcat에서 제공 되는 에러 페이지를 보았을 것이다.

이번 포스팅에선 이런 에러 페이지를 커스터마이징 하기 위한 내용들을 알아보려고 한다.

 

▶ 공식 문서 참고

https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-error-handling

 

들어가기 앞서 공식 doc에 있는 내용을 먼저 살펴 보도록 하자.

 

By default, Spring Boot provides an /error mapping that handles all errors in a sensible way, and it is registered as a “global” error page in the servlet container.

 => Spring Boot는 모든 오류를 적절한 방식으로 처리하는 /error 맵핑을 제공하며, servlet container에 "global" 에러 페이지로 등록된다.

 

For machine clients, it produces a JSON response with details of the error, the HTTP status, and the exception message.
 => 머신 클라이언트의 경우, error 상세내용, HTTP status 및 exception message를 포함하여 JSON 응답을 생성한다.

For browser clients, there is a “whitelabel” error view that renders the same data in HTML format
(to customize it, add a View that resolves to error).
 => 브라우저 클라이언트의 경우, 동일한 데이터를 HTML 형식(에러 처리 View를 커스텀 하여 추가하기 위하여)으로 렌더링 하는 “whitelabel” error view 가 있다.

To replace the default behavior completely, 
 => 기본 처리방법을 완전히 바꾸기 위하여,
you can implement ErrorController and register a bean definition of that type or add a bean of type ErrorAttributes 
 => ErrorController를 구현하고 해당 유형의 bean 정의를 등록하거나 ErrorAttributes 유형의 bean을 추가할 수 있다.
to use the existing mechanism but replace the contents.
 => 기존 에러 처리방법은 사용하지만 에러 내용을 대체 할 수 있다.

 

1. SpringBoot 기본적인 에러처리

▶ 1. 기본적인 에러 처리

1.1 html

html 응답

1.2 json

json 응답

 

스프링부트는 자동 구성을 이용하여 화이트라벨(Whitelabel) 오류 페이지를 기본으로 노출 한다.
물론 화면에 스택 트레이스를 표시하는 것보단 괜찮지만, 일반적으로 싸이트 마다 어울리는 특정 페이지를 제작하여 해당 페이지를 노출하곤 한다.
이렇게 설정하고 싶을 때 애플리케이션 오류 페이지를 사용자 정의 할 수 있는데, 그 방법에 대해 알아 보려고 한다.

스프링부트가 자동으로 구성한 기본 오류 핸들러는 'error'뷰를 찾고, 없을 경우 화이트라벨(Whitelabel) 뷰를 사용한다.
이 에러 페이지는 스프링부트에 의해 만들어진 페이지 이며, 이런 기본적인 에러 처리를 하는 곳이 BasicErrorController 이다.

▶ 2. Properties

spring boot의 오류 처리에 대한 properties

server.error.include-exception : 오류 응답에 exception의 내용을 포함할지 여부 (TRUE, FALSE)
server.error.include-stacktrace : 오류 응답에 stacktrace 내용을 포함할지 여부 (ALWAYS, NEVER, ON_TRACE_PARAM)
server.error.path : 오류 응답을 처리할 핸들러(ErrorController)의 path
server.error.whitelabel.enabled : 브라우저 요청에 대해 서버 오류시 기본으로 노출할 페이지를 사용할지 여부 (TRUE, FALSE)

server.error.whitelabel.enabled의 기본값이 true이기 때문에 위에서와 같이 오류 페이지가 노출되고 있었다.

 

그럼 다음과 같이 프로퍼티 설정 후 다시 오류 페이지를 노출 시켜 보자.

include-exception, nclude-stacktrace를 활성화하면 stacktrace도 노출되는 것을 볼 수 있다.

server:
  error:
    include-exception: true # 오류 응답에 exception의 내용을 포함할지 여부
    include-stacktrace: always # 오류 응답에 stacktrace 내용을 포함할 지 여부

html 응답
json 응답

▶ 3. 기본 CustomErrorPage 설정

If you want to display a custom HTML error page for a given status code, you can add a file to an /error folder.
 => 오류 상태 코드에 따라 사용자 정의 HTML 오류 페이지를 표시하려는 경우 파일을 /error폴더에 추가 할 수 있다.

Error pages can either be static HTML (that is, added under any of the static resource folders) or be built by using templates.
 => 오류 페이지는 정적 HTML(정적 자원 폴더 아래에 추가된)이거나 템플릿을 사용하여 작성 될 수 있다.

The name of the file should be the exact status code or a series mask.
 => 파일 이름은 정확한 상태 코드 또는 시리즈 마스크 여야 한다.

 

ex1) 404 HTML 파일 폴더구조 (기본 html)

src/
 +- main/
     +- java/
     |   + <source code>
     +- resources/
         +- public/(static ... 등)
             +- error/
             |   +- 404.html
             +- <other public assets>

ex2) 404 HTML 파일 폴더구조 (템플릿 사용, thymeleaf)

src/
 +- main/
     +- java/
     |   + <source code>
     +- resources/
         +- templates/
             +- error/
             |   +- 404.html
             +- <other templates>

 

나와 같은 경우는 thymeleaf를 예로들어 404.html 파일을 만들어 보도록 한다.

 

※ 참고

에러 뷰에서 다음 오류 속성을 표기할 수 있도록 제공 한다.
 - timestamp : 오류 발생 시각
 - status : HTTP 상태 코드
 - error : 오류 발생 이유
 - exception : 예외 클래스 이름
 - message : 예외 메시지
 - errors : BindingResult 예외로 발생한 모든 오류
 - trace : 예외 스택 트레이스
 - path : 오류가 발생했을때 요청한 URL 경로

 

ex) 404.html (thymeleaf)

<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Test Error Page!</title>
    <link rel="stylesheet" th:href="@{/css/style.css}"></link>
</head>
<body>
    <div class="errorPage">
        <span class="errorHead">Error!</span><br />
        <p th:text="${'path: ' + path}"></p>
        <p th:text="${'status: ' + status}"></p>
        <p th:text="${'timestamp: ' + timestamp}"></p>
        <p th:text="${'error: ' + error}"></p>
        <p th:text="${'errors: ' + errors}"></p>
        <p th:text="${'exception: ' + exception}"></p>
        <p th:text="${'message: ' + message}"></p>
        <p th:text="${'trace: ' + trace}"></p>
    </div>
</body>
</html>

▶ 4. 특정 경로 CustomErrorPage 설정 하기

 - "ErrorController"를 implements 받은 custom controller 를 추가하면 된다.

 - getErrorPath 를 override 하여 error page 경로를 지정한다. (default : /error)

ex) CustomErrorController

@Controller
public class CustomErrorController implements ErrorController {
    private String VIEW_PATH = "/errors/";

    @RequestMapping(value = "/error")
    public String handleError(HttpServletRequest request) {
        Object status = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);

        if(status != null){
            int statusCode = Integer.valueOf(status.toString());

            if(statusCode == HttpStatus.NOT_FOUND.value()){
                return VIEW_PATH + "404";
            }
            if(statusCode == HttpStatus.FORBIDDEN.value()){
                return VIEW_PATH + "500";
            }
        }
        return "error";
    }

    @Override
    public String getErrorPath() {
        return "/error";
    }
}

 

혹시나 하여 jsp로도 에러 페이지 생성 하여 테스팅 해보았다.

ex) JSP 폴더 구조

src/
 +- main/
     +- java/
     |    + <source code>
     +- resources/
     |    + <static code>
     +- webapp/
          +- WEB_INF/
               +- error/
               |    +- 404.jsp
               +- <other jsps>

 

ex) WEB_INF/jsp/erros/404.jsp

taglib 를 import, c:out 을 이용하여 exception을 출력해줄 수 있다.

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Test Error Page!</title>
</head>
<body>
    <div class="errorPage">
        <span class="errorHead">Error!</span><br />
        <p>request_uri : <c:out value="${requestScope['javax.servlet.error.request_uri']}"/></p>
        <p>status_code : <c:out value="${requestScope['javax.servlet.error.status_code']}"/></p>
        <p>servlet_name : <c:out value="${requestScope['javax.servlet.error.servlet_name']}"/></p>
        <p>exception : <c:out value="${requestScope['javax.servlet.error.exception']}"/></p>
        <p>servlet_name : <c:out value="${requestScope['javax.servlet.error.servlet_name']}"/></p>
        <p>message : <c:out value="${requestScope['javax.servlet.error.message']}"/></p>
    </div>
</body>
</html>

 

나와 같은 경우 일단 thymeleaf를 사용하고,  기본 /error/ 경로에 커스터 마이징한 에러 페이지를 노출 할 예정이다.


댓글을 달아 주세요

  1. chobo 2020.07.08 11:59

    안녕하세요 도움되는 블로그 글 항상 감사합니다.
    제가 초보인데.. 에러처리에 해당하는 화면을 html응답과 json응답으로 나눠서 보여주셨는데 json응답을 확인하는 방법을 모르겠어서 댓글 남깁니다.