3 분 소요

 인프런 스프링 MVC 2편 - 백엔드 웹 개발 활용 기술편을 학습하고 정리한 내용 입니다.

스프링 부트 - 오류페이지

지금까지 예외 처리 페이지를 만들기 위해서 다음과 같은 복잡한 과정이 있었다.

  • WebServerCustomizer 생성
  • 예외 종류에 따라서 ErrorPage를 추가
    • 예외 처리 용 컨트롤러 ErrorPageController를 생성

스프링 부트는 이런 과정을 모두 기본으로 제공

  • ErrorPage를 자동으로 등록한다. 이때 /error라는 경로로 기본 오류 페이지를 설정한다.
    • new ErrorPage("/error"), 상태 코드와 예외를 설정하지 않으면 기본 오류 페이지로 사용된다.
    • 서블릿 밖으로 예외가 발생하거나, response.sendError(...)가 호출되면 모든 오류는 /error를 호출하게 된다.
  • BasicErrorController라는 스프링 컨트롤러를 자동으로 등록한다.
    • ErrorPage에서 등록한 /error를 매핑 해서 처리하는 컨트롤러다.

참고
ErrorMvcAutoConfiguration이라는 클래스가 오류 페이지를 자동으로 등록하는 역할을 한다.

스프링 부트가 제공하는 기본 오류 메커니즘을 사용하도록

WebServerCustomizer에 있는 @Component는 주석 처리 하자.

이제 오류가 발생했을 때 오류 페이지로 /error를 기본으로 요청한다.

스프링 부트가 자동 등록한 BasicErrorController는 이 경로를 받는다.

오류 페이지 등록

개발자는 오류 페이지만 등록

개발자는 BasicErrorController가 제공하는 룰과 우선순위에 따라 오류 페이지 화면만 등록하면 된다.

뷰 선택 우선 순위

  1. 뷰 템플릿
    • resources/templates/error/500.html
    • resources/templates/error/5xx.html
  2. 정적 리소스(static, public)
    • resources/static/error/400.html
    • resources/static/error/404.html
    • resources/static/error/4xx.html
  3. 적용 대상이 없을 때 뷰 이름(error)
    • resources/templates/error.html

해당 경로 위치에 HTTP 상태 코드 이름의 뷰 파일을 넣어두면 된다.

뷰 템플릿이 정적 리소스보다 우선 순위가 높고, 404, 500처럼 구체적인 것이 5xx처럼 덜 구체적인 것 보다 우선 순위가 높다.

5xx, 4xx 라고 하면 500대 400대 오류를 처리해 준다.

오류 뷰 템플릿 추가

4xx.html을 만들어서 추가해 보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE HTML>  
<html xmlns:th="http://www.thymeleaf.org">  
<head>  
    <meta charset="utf-8">  
</head>  
<body>  
  
<div class="container" style="max-width: 600px">  
    <div class="py-5 text-center">  
        <h2>4xx 오류 화면 스프링 부트 제공</h2>  
    </div>  
  
    <div>  
        <p>오류 화면 입니다.</p>  
    </div>  
  
    <hr class="my-4">  
  
</div> <!-- /container -->  
  
</body>  
</html>

기존에 404, 500이 있어서 400 컨트롤러를 하나 만들고 4xx가 호출 되는지 보자.

1
2
3
4
@GetMapping("/error-400")  
public void error400(HttpServletResponse response) throws IOException {  
    response.sendError(400, "400 오류 !!!");  
}

400를 호출하니 400이 없기 때문에 4xx가 호출 됬다.

404는 있기 때문에 404가 호출 된다.

BasicErrorController가 제공하는 기본 정보들

BasicErrorController는 다음 정보를 model에 담아서 뷰에 전달한다.

뷰 템플릿은 이 값을 활용해서 출력 할 수 있다.

1
2
3
4
5
6
7
8
* timestamp: Fri Feb 05 00:00:00 KST 2021 
* 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`)

그럼 뷰에서 이걸 출력해 보자.

뷰 템플릿 오류 정보 추가

resources/templates/error/500.html

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
32
33
<!DOCTYPE HTML>  
<html xmlns:th="http://www.thymeleaf.org">  
<head>  
    <meta charset="utf-8">  
</head>  
<body>  
  
<div class="container" style="max-width: 600px">  
    <div class="py-5 text-center">  
        <h2>500 오류 화면</h2>  
    </div>  
  
    <div>  
        <p>오류 화면 입니다.</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>  
    </ul>  
  
    <hr class="my-4">  
  
</div> <!-- /container -->

오류 정보들이 null이 많이 나오는데,

오류 관련 내부 정보들을 고객에게 노출하는 것은 좋지 않다.

고객이 해당 정보를 읽어도 혼란만 더해지고, 보안상 문제가 될 수도 있다.

그래서 BasicErrorController에서 다음 오류 정보를 model에 포함할 지 여부를 선택할 수 있다.

다음과 같이 설정 파일에 넣어 주면 된다.

노출 안하는게 맞다.

설정 단계

  • never : 사용 안함
  • always : 항상 사용
  • on_param : 파라미터가 있을 때 사용

on_param은 파라미터가 있으면 해당 정보를 노출 한다. 디버그 시 문제를 확인 하기 위해 사용할 수 있다.

하지만 운영에선 사용하지 말자.

실무에서는 이것들을 노출하면 안된다! 사용자에게는 이쁜 오류 화면과 고객이 이해할 수 있는 간단한 오류 메시지를 보여주고 오류는 서버에 로그로 남겨서 로그로 확인해야 한다

스프링 부트 오류 관련 옵션

  • server.error.whitelabel.enabled=true : 오류 처리 화면을 못 찾을 시, 스프링 whitelabel 오류 페이지 적용
  • server.error.path=/error : 오류 페이지 경로, 스프링이 자동 등록하는 서블릿 글로벌 오류 페이지 경로와 BasicErrorController오류 컨트롤러 경로에 함께 사용한다.

확장 포인트

에러 공통 처리 컨트롤러의 기능을 변경하고 싶으면 ErrorController인터페이스를 상속 받아서 구현하거나 BasicErrorController 상속 받아서 기능을 추가하면 된다.

댓글남기기