이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.

  • Spring Boot는 처리되지 않은 오류를 어떻게 /error와 기본 응답으로 연결하는가?
  • BasicErrorController, ErrorAttributes, Whitelabel Error Page는 각각 어떤 역할인가?
  • Boot 기본 에러 처리를 어디까지 믿고, 어디부터 애플리케이션 오류 계약을 직접 만들어야 하는가?

개요

Spring Boot는 웹 애플리케이션에서 기본 에러 처리 인프라를 자동 설정한다. 애플리케이션이 예외를 직접 처리하지 못하거나 Servlet 컨테이너가 오류 디스패치를 수행하면 기본적으로 /error 경로로 이어진다.

이때 BasicErrorController가 요청을 받고, ErrorAttributes가 오류 응답에 필요한 정보를 제공한다. 별도 에러 페이지가 없으면 Whitelabel Error Page가 HTML 응답으로 보일 수 있다.

동작 흐름

컨트롤러에서 예외가 발생하고 @ExceptionHandler나 MVC 기본 resolver가 처리하지 못하면 오류는 컨테이너의 에러 처리 흐름으로 넘어갈 수 있다. Boot는 이 흐름을 /error endpoint에 연결한다.

BasicErrorController는 클라이언트가 원하는 응답 형식과 설정에 따라 HTML 또는 JSON 형태의 기본 응답을 만든다. 브라우저가 HTML을 선호하면 에러 페이지가, API 클라이언트가 JSON을 선호하면 에러 속성 기반 응답이 내려갈 수 있다. Problem Details가 활성화된 환경에서는 일부 오류가 ProblemDetail 기반 표현으로 내려갈 수도 있다.

ErrorAttributes는 timestamp, status, error, path 같은 기본 속성을 제공한다. server.error.include-* 계열 설정에 따라 message, exception, stacktrace 포함 여부가 달라질 수 있다. 운영 환경에서는 내부 예외 정보가 외부로 나가지 않도록 특히 조심해야 한다.

기존 MVC 예외 문서와 연결되는 지점

기존 MVC 예외 처리 문서에서 정리한 BasicErrorController, Whitelabel Error Page, ErrorAttributes는 모두 마지막 방어선의 구성요소다. 이들을 먼저 이해하면 @ControllerAdvice가 왜 필요한지도 선명해진다.

@ControllerAdvice는 애플리케이션이 예측한 실패를 공식 응답 계약으로 바꾼다. BasicErrorController는 그보다 뒤에서 처리되지 않은 실패를 기본 형식으로 변환한다. 둘은 경쟁 관계가 아니라 서로 다른 레벨의 방어선이다.

커스터마이징 기준

ErrorAttributes를 커스터마이징하면 기본 오류 응답의 필드를 바꿀 수 있다. 하지만 API의 모든 오류를 여기서 해결하려고 하면 실패 의미를 잃기 쉽다. 검증 실패, 비즈니스 실패, 인증 실패처럼 의미가 분명한 오류는 전역 Advice나 Security entry point에서 처리하는 편이 좋다.

기본 에러 처리는 예상 밖 장애, 정적 리소스 오류, 미처리 상태 코드처럼 마지막까지 떨어지는 오류를 담당하게 둔다. 운영에서는 여기에 추적 ID를 붙이거나 내부 정보를 숨기는 정책을 확인한다.

코드 예제

@Component
public class SafeErrorAttributes extends DefaultErrorAttributes {
 
    @Override
    public Map<String, Object> getErrorAttributes(
            WebRequest webRequest,
            ErrorAttributeOptions options
    ) {
        Map<String, Object> attributes = super.getErrorAttributes(
                webRequest,
                options.excluding(ErrorAttributeOptions.Include.EXCEPTION,
                        ErrorAttributeOptions.Include.STACK_TRACE));
 
        attributes.put("code", "INTERNAL_ERROR");
        return attributes;
    }
}

이 예제는 기본 에러 속성에서 내부 예외와 스택트레이스를 제외하고 애플리케이션 오류 코드를 추가하는 방향을 보여 준다. 실제로는 관측 시스템의 trace id, request id와 함께 설계하는 것이 좋다.

실전 팁

  • 기본 에러 응답은 마지막 방어선으로 보고, 공식 API 오류 계약은 Advice에서 우선 처리한다.
  • 운영 환경에서는 exception, trace, message 노출 설정을 반드시 확인한다.
  • Spring Boot의 Problem Details 설정을 켰다면 /error와 Advice 응답의 형식이 서로 어긋나지 않는지 확인한다.
  • HTML 화면과 API 오류 응답의 요구가 다르면 같은 /error라도 응답 형식을 분리해서 생각한다.
  • Whitelabel Error Page가 보이면 “처리되지 않은 오류가 마지막 방어선까지 갔다”고 해석한다.
  • 기본 에러 응답에도 추적 가능한 요청 식별자를 포함할지 검토한다.

위험 신호!

  • API 클라이언트가 Boot 기본 에러 JSON 필드에 강하게 의존한다.
  • 운영 응답에 스택트레이스나 예외 클래스명이 노출된다.
  • Problem Details와 커스텀 오류 DTO가 섞여 같은 API에서 서로 다른 오류 형식이 나온다.
  • 의도한 비즈니스 실패가 전역 Advice를 거치지 않고 /error까지 떨어진다.
  • HTML 에러 페이지와 API 오류 응답을 같은 메시지 정책으로 처리한다.
  • ErrorAttributes에서 모든 비즈니스 예외를 문자열로 분기한다.

확인 질문

확인 질문

  • Spring Boot의 기본 에러 처리에서 BasicErrorController는 무엇을 하는가?
    • /error 요청을 받아 기본 에러 페이지나 응답 본문을 생성한다.
  • ErrorAttributes는 어떤 역할인가?
    • 기본 에러 응답에 들어갈 속성을 제공하고 커스터마이징 지점을 제공한다.
  • Whitelabel Error Page가 보인다는 것은 무엇을 의미하는가?
    • 애플리케이션에서 처리되지 않은 오류가 Boot의 기본 HTML 에러 처리까지 도달했다는 뜻이다.

참고 문서