Spring MVC/03.예외 처리

[spring 예외 처리] 01.설정을 통한 예외 처리

  • -

애플리케이션이 동작하다보면 당연히 수많은 예외가 발생한다. 자바에서 예외 처리를 위해서는 try ~ catch를 사용하는데 사실 이 따분한 코드는 작성하기가 매우 귀찮다. 따라서 스프링에서는 대부분 예외가 Runtime 계열의 예외로 wrapping 되어 자동으로 throws 되게 하고  WAS가 처리하도록 위임하거나 @Controller에서 프로그래밍적으로 처리한다.

 

error 페이지는 예상치 못했던 클라이언트의 요청에 대해 WAS가 응답하는 결과라고 볼 수 있다. 하지만 WAS가 보여주는 error 페이지는 너무나 흉찍하고 여기서 보여지는 error 정보들을 헤커의 먹이감이 되기 때문에 반드시 사용자 정의 페이지로 처리해주어야 한다.

흉찍한 에러 페이지, 미관상 안좋기도 하지만 무엇보다 사이트의 취약점을 노출하게 된다.

이번 포스트에서는 WAS에게 처리를 위임하는 형태를 살펴보자.

 

준비작업

기본적인 프로젝트의 의존성은 아래와 같다. template으로 mustache를 사용하고 있음을 주의하자.

여기서는 404, 405 오류와 500 오류에 대해서 처리해보도록 하자.

에러 페이지 작성

먼저 templates 위치에 error.html을 아래와 같이 작성해보자. 우리 사이트는 어떤 오류가 발생하면 모두 아래의 페이지를 표현할 계획이다.

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>문제가 있음</h1>
</body>
</html>

 

문제를 발생하는 controller 준비

@Controller
public class ExceptionTestController {

    @PostMapping("/notget")
    public String notGet() {
        return "index";
    }

    @GetMapping("/exception")
    public String exception() {
        int i = 1 / 0;
        return "index";
    }

    @PostMapping("api/notget")
    public String apinotGet() {
        return "get만";
    }

    @GetMapping("/api/exception")
    public String apiexception() {
        int i = 1 / 0;
        return "예외";
    }
}

 

spring legacy에서의 예외 처리

 

web.xml  설정

가장 전통적인 방법은 web.xml을 활용하는 방식이다. 

spring 훨씬 이전부터 servlet에서는 오류가 발생하면 최종적으로 WAS가 에러를 받아서 지정된 error 페이지로 연동하도록 web.xml에 설정할 수 있었다.

다음의 설정을 web.xml에 추가해보자.

<web-app>    
    . . .
	<error-page>
		<error-code>404</error-code>
		<location>/error/404</location>
	</error-page>
	<error-page>
		<error-code>405</error-code>
		<location>/error/405</location>
	</error-page>
	<error-page>
		<error-code>500</error-code>
		<location>/error/500</location>
	</error-page>
</web-app>

 

Controller 설정

이제 error-code에 지정해둔 404, 405, 500오류가 발생하면 get 방식으로 /error/{상태코드}라는 요청을 다시 날리게 된다. 따라서 @Controller에 이 요청을 처리할 request handling method를 작성해보자.

@GetMapping("/error/{statusCode}")
public String getErrorPage(@PathVariable String statusCode) {
    return "error/"+statusCode;
}

 

동작 확인

이제 브라우저의 주소창에 아래와 같이 3가지 요청을 해보면 모두 에러 페이지로 잘 연결되는 것을 확인할 수 있다.

<ul>
	<li><a href="${root}/notget">post만 가능: 405</a>
	<li><a href="${root}/exception">예외: 500</a>
	<li><a href="${root}/notexist">없는 페이지: 404</a>
</ul>

 

Spirng Boot 사용 시

SpringBoot에서는 더이상 web.xml이 존재하지 않는다. 따라서 예외에 대한 처리도 application.properties에서 설정으로 처리한다.

Whiteable error page

spring boot에서는 was에 오류가 도착한 후 별다른 처리가 없으면 아래처럼 whiteable error page가 연결된다. whiteable error page는 일반적인 http 요청 뿐 아니라 ajax를 통한 요청에 대해서도 제공된다.

http 요청에 대한 오류 페이지

 

ajax 요청에 대한 오류 페이지

위의 오류 페이지가 동작하는 이유는 application.properties에 아래의 설정이 기본으로 잡혀있기 때문이다.

server.error.whitelabel.enabled=true

필요에 따라 추가로 다음의 설정을 해볼 수도 있다.

# 스프링 부트의 whitelabel error page 사용 여부, defaul: true
# 미적용 시 WAS 기본의 오류 페이지 전송 가능
server.error.whitelabel.enabled=true

# 에러 발생시 처리 경로, default : /error
server.error.path=/error

# 응답 시 바인딩된 에러에 대한 표시 여부: [NEVER, ALWAYS, ON_PARAM], default: NEVER
server.error.include-binding-errors=ALWAYS

# 응답 시 exception 내용 포함 여부, default: false
server.error.include-exception=true

# 응답 시 message 포함 여부:[NEVER, ALWAYS, ON_PARAM], default : NEVER
server.error.include-message= NEVER

# 응답 시 stack trace 포함 여부: [NEVER, ALWAYS, ON_PARAM], default: NEVER
server.error.include-stacktrace=ALWAYS

#404 상황에서 예외를 발생시킬 것인지
spring.mvc.throw-exception-if-no-handler-found=true

사실 오류 페이지에서 오류의 상세한 내용을 보여준다는 것은 대부분의 클라이언트에게 불필요한 내용이기 때문에 구지 설정을 변경할 필요는 없어보인다.

여기서 기억할 부분은 whitelabel error page의 사용을 허용하는 부분과 에러 페이지 처리를 위한 경로가 /error 라는 점이다.

 

하지만 이 오류 페이지도 못생겨서 클라이언트에게 서비스 하기에는 당연히 불충분하고 사용자 정의의 에러 페이지로 연결하는 것이 바람직하다.http 요청에 대한 오류 페이지의 내용을 잘 살펴보면 /error 에 대한 명시적인 mapping이 없기 때문에 현재의 페이지를 표시하고 있다고 알려주고 있다. 

그럼 어떤 설정을 어떻게 처리하면 사용자 정의의 오류 페이지를 확인할 수 있을까?

 

에러 페이지 매핑

application.properties에 의하면 WAS에 오류가 전달되었을 때 WAS는 /error를 요청하고 이 요청에 대한 mapping이 없을 경우 whiteable error page가 표시된다. 내부적으로 /error 가 요청되면 찾는 에러페이지는 /error.html 등이다. 따라서 아래와 같이 에러 페이지를 만들어두면 기본 에러들을 다 처리할 수 있다.

 

또는 에러 상태별 예외 처리 페이지를 사용하려면 error 폴더 밑에 에러 상태별 페이지를 만들어두는 것만으로도 충분하다. 예를 들어 아래는 404, 405, 500 예외에 대한 페이지를 의미한다.

 

템플릿 페이지에서 오류 내용 확인

spring boot에서 오류 페이지를 연결할 때는 다음의 속성을 추가해주기 때문에 사용 가능한데 사실 오류 페이지에 자세한 정보를 넣어줄 필요가 없기는 하다.

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>문제가 있음</h1>
	<ul>
		<li>발생시간: {{timestamp}}</li>
		<li>호출경로: {{path}}</li>
		<li>상태: {{status}}</li>
		<li>메시지: {{message}}</li>
	</ul>
</body>
</html>

 

참고로 위임형의 처리 흐름은 아래와 같이 정리해볼 수 있다.

템플릿 엔진에 따라 jsp 또는 html

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.