예외 종류별 처리 표준은 Spring이 던지는 요청 오류까지 Advice에 등록하라고 정했고, 근거는 이랬다.

@Valid·JSON 파싱 실패만 등록하면 타입 불일치·필수 파라미터 누락·405·415·없는 경로가
500으로 새어 모니터링에서 서버 장애로 잡힌다.

「모니터링이 서버 장애로 본다」가 규칙의 이유였다. 실제로 500이 나가는지 재야 했다.


주장 — 등록하지 않은 요청 오류는 500으로 나간다

@Valid 실패와 JSON 파싱 실패만 Advice에 등록하면,
타입 불일치·필수 파라미터 누락·405·415·없는 경로는 500으로 나간다.

근거 종류는 1(기술 사실)이다.


반증 조건 — 다섯 중 하나라도 500이 아니면 반증이다

  • refuted — 두 환경 중 하나라도 다섯 중 하나라도 500이 아니다
  • supported — 두 환경 모두 다섯 전부 500이다
  • inconclusive — 서버가 뜨지 않거나, 대조군 @Valid 실패가 Advice를 타지 않는다

설계 — catch-all을 빼고 표준이 말한 그 상태를 그대로 만든다

Advice에는 MethodArgumentNotValidExceptionHttpMessageNotReadableException 핸들러만 둔다. Exception catch-all을 두지 않는다. 임베디드 톰캣을 실제로 띄우고(server.port=0) java.net.http.HttpClient로 다섯 요청을 보냈다.

타입 불일치   GET  /probe?count=abc     (count 는 int)
필수 누락     GET  /probe
메서드        DELETE /probe
미디어 타입   POST /probe  text/plain
없는 경로     GET  /no-such-path

대조군은 @Valid 실패(POST /probe 빈 JSON)다. Advice가 살아 있는지 확인하는 자리다. 환경은 Spring Boot 3.5.16과 4.1.1이다.


결과 — 500이 하나도 없었다

PROBE boot=3.5.16 mismatch=400 missing=400 method=405 media=415 nopath=404 valid=400 valid_marked=true
PROBE boot=4.1.1  mismatch=400 missing=400 method=405 media=415 nopath=404 valid=400 valid_marked=true

다섯이 전부 의미에 맞는 상태로 나갔다. 대조군은 handledBy=advice kind=valid 400이라 Advice도 살아 있었다. 판정은 refuted다.


예상과 달랐던 점 — 새는 것은 상태 코드가 아니라 응답 형식이다

본문을 보면 다른 것이 드러난다.

GET /probe?count=abc -> 400
{"timestamp":"...","status":400,"error":"Bad Request","path":"/probe"}

POST /probe {} -> 400
handledBy=advice kind=valid

다섯은 Boot 기본 /error JSON으로 나가고, Advice를 탄 요청만 우리 형식으로 나간다. 상태 코드는 제대로 붙지만 같은 400이 두 가지 모양으로 나간다. 클라이언트는 어느 형식이 올지 모른 채 둘 다 다뤄야 한다.

표준의 규칙(요청 오류도 Advice에 등록한다)은 이 결과로도 여전히 쓸모가 있다. 다만 이유가 「500으로 샌다」가 아니라 「응답 형식이 갈린다」로 바뀐다. 이건 내 해석이고, 「형식이 갈린다」까지가 측정된 사실이다.


이 결과가 표준에 남기는 것 — 규칙은 두고 근거 문장을 다시 쓴다

측정된 것은 둘이다. 상태 코드는 새지 않는다(반증된 부분), 형식은 갈린다(원본 출력에 그대로 있다). 규칙을 지울 이유는 이 실험에 없지만, 지금 글에 적힌 근거는 틀렸다.

규칙은 바로 고치지 않는다. 표준 글에 > 반증: 줄을 달고 kind: 모순 이슈에서 근거 문장을 다시 쓸지 정한다.


정리

  • 다섯 요청이 전부 400·400·405·415·404로 나갔다. 두 Boot 버전이 같았다
  • 「500으로 샌다」는 기본 설정 Spring Boot MVC에서 성립하지 않는다
  • 대신 응답 형식이 갈린다. Advice를 탄 것만 우리 형식이고 나머지는 Boot 기본 /error JSON이다
  • 규칙을 지우자는 결론이 아니다. 근거 문장을 바꿀지는 모순 이슈에서 정한다

자신만의 철학을 만들어가는 중입니다.
최상단으로 이동했습니다!
확대 이미지

댓글남기기