[데브코스] Spring Boot 인증·인가(Auth) (25강) - Authorization 헤더 누락 시 MissingRequestHeaderException 처리하기

zuno·2026년 1월 13일

이번 강의에서는 Authorization 헤더가 아예 전달되지 않았을 때
@NotBlank 검증 에러가 아니라 MissingRequestHeaderException 이 발생하는지,
그리고 이를 GlobalExceptionHandler에서 직접 처리하는 이유를 정리했다.


🚨 문제 상황

Postman에서 인증이 필요한 API 요청을 보낼 때
Authorization 헤더를 아예 제거하고 요청을 보내면 다음과 같은 에러가 발생했다.

{
  "status": 400,
  "error": "Bad Request",
  "message": "Required request header 'Authorization' is not present"
}

처음에는 이렇게 생각했다.

"Authorization에 @NotBlank를 붙였으니까
NotBlank 검증 오류가 떠야 하는 거 아닌가?"

하지만 실제로는 전혀 다른 예외가 발생했다.


❓ 왜 @NotBlank가 아니라 MissingRequestHeaderException 인가?

핵심은 Spring MVC의 요청 처리 순서에 있다.

요청 흐름 정리

  1. 클라이언트 요청 도착
  2. Spring이 컨트롤러 메서드 파라미터 바인딩 시도
  3. @RequestHeader("Authorization") 확인
  4. ❌ 헤더 자체가 없음
  5. 👉 MissingRequestHeaderException 발생
  6. ❌ Bean Validation 단계(@NotBlank)까지 가지도 못함

즉,

  • @NotBlank
    값이 존재하지만 비어있을 때 검사
  • MissingRequestHeaderException
    헤더 자체가 존재하지 않을 때 발생

그래서 이 상황에서는 @NotBlank가 동작할 기회조차 없다.


🧠 정리하면

상황발생 예외
Authorization 헤더 없음MissingRequestHeaderException
Authorization: ""@NotBlank 검증 오류
Authorization: "Bearer xxx"정상

🛠 GlobalExceptionHandler에서 예외 처리

이 예외를 그대로 두면 Spring 기본 에러 응답(JSON 구조가 제각각)이 내려간다.
그래서 우리 프로젝트의 RsData 포맷에 맞게 직접 처리했다.

@ExceptionHandler(MissingRequestHeaderException.class)
public ResponseEntity<RsData<Void>> handle(MissingRequestHeaderException ex) {
    return new ResponseEntity<>(
            new RsData<>(
                    "400-1",
                    "%s-%s-%s".formatted(
                            ex.getHeaderName(),
                            "NotBlank",
                            ex.getLocalizedMessage()
                    )
            ),
            BAD_REQUEST
    );
}

🔍 코드 한 줄씩 설명

1️⃣ @ExceptionHandler(MissingRequestHeaderException.class)

  • Authorization 헤더가 아예 없을 때
  • Spring이 던지는 예외를 여기서 잡는다

2️⃣ ex.getHeaderName()

ex.getHeaderName()
  • 누락된 헤더 이름 반환
  • 여기서는 항상 "Authorization"

3️⃣ "NotBlank" 를 문자열로 넣은 이유

  • 실제 Bean Validation은 아니지만
  • 프론트엔드에게 "이 값은 비어 있으면 안 된다"는 의미를 전달
  • 에러 포맷 통일 목적

4️⃣ ex.getLocalizedMessage() 의 역할

ex.getLocalizedMessage()

👉 예외 객체가 기본적으로 가지고 있는 "사람용 설명 문장"

반환되는 값 예시:

Required request header 'Authorization' is not present

중요한 점은,

  • ❌ 예외 클래스명, 스택트레이스 포함 안 됨
  • ⭕ 핵심 원인 설명만 반환
  • ⭕ API 응답용으로 깔끔함

즉,
에러 메시지가 줄어든 게 아니라 정제된 것이다.


📦 최종 응답 메시지 예시

Authorization-NotBlank-Required request header 'Authorization' is not present

이 메시지 하나로 다음을 모두 전달한다.

  • 어떤 값이 문제인지
  • 어떤 조건을 기대했는지
  • 왜 실패했는지

✅ 이번 강의 핵심 요약

  • @RequestHeader가 없으면 검증 이전에 예외가 터진다
  • @NotBlank값이 존재할 때만 의미가 있다
  • MissingRequestHeaderException은 직접 핸들링하는 게 좋다
  • ex.getLocalizedMessage()
    → API 응답용으로 가장 적절한 에러 설명이다

이번 강의는
Spring의 요청 바인딩 순서를 이해했는지가 핵심 포인트였다.

0개의 댓글