본문 바로가기

Spring

서버 마이그레이션 후 API 오류? 슬래시 하나에 숨겨진 Spring Boot의 진실 (PathPatternParser)

📝 TIL: 왜 API는 마이그레이션 전후로 다르게 동작했을까?

의문

최근 서버 마이그레이션(Java/Legacy Spring/Tomcat → Kotlin/Spring Boot/Corretto 21)을 진행했습니다. 그런데 기존에 정상적으로 작동하던 API 엔드포인트 중 하나가 404 Not Found 에러를 뱉기 시작했습니다. 분석 결과, 문제는 URL 경로 끝에 붙은 슬래시(/) 하나 때문이었습니다 (.../resource/ vs .../resource).

"아니, 슬래시 하나 때문에? 왜 과거에는 문제가 없었고, 지금은 안 되는 걸까?"

이 사소해 보이는 차이가 불러온 오류가 저의 가장 큰 호기심이었습니다. 이 기술적 차이의 근본 원인을 파헤쳐 보기로 했습니다.

오늘 배운 것: '관용'에서 '엄격'으로의 변화

문제의 핵심은 Spring 프레임워크의 '기본 URL 처리 전략'이 변경되었기 때문이었습니다. 과거와 현재의 서버 환경이 URL을 해석하는 방식에 결정적인 차이가 있었습니다.

1. 과거의 서버 환경: 관대한 AntPathMatcher

  • 환경: Java, Legacy Spring, 외장 Tomcat
  • 동작 방식: 과거 Spring Framework의 기본값이었던 AntPathMatcher는 URL 경로를 비교적 유연하게 해석했습니다. 개발자가 특별히 엄격한 규칙을 설정하지 않는 한, /resource/resource/의미상 동일한 요청으로 간주하고 너그럽게 처리해 주었습니다.
  • 결과: 클라이언트(안드로이드 앱)가 URL 끝에 불필요한 슬래시를 포함하여 .../resource/와 같은 요청을 보내도, 서버는 이를 .../resource로 인식하고 정상적으로 처리했습니다.

2. 현재의 서버 환경: 엄격한 PathPatternParser

  • 환경: Kotlin, Spring Boot 2.6+ (Spring Framework 5.3+), 내장 Tomcat
  • 동작 방식: Spring Boot 2.6 (Spring Framework 5.3)부터는 PathPatternParser라는 새로운 경로 해석기가 기본값으로 채택되었습니다. 이 해석기는 다음과 같은 이유로 URL 처리가 훨씬 엄격합니다.
    • 성능 향상: PathPatternParser는 URL 패턴을 미리 파싱하여 런타임 시 요청 처리 속도가 AntPathMatcher보다 빠릅니다.
    • 웹 표준 및 RESTful 원칙 준수: URL 표준(RFC 3986)에 따르면 /resource/resource/명백히 다른 경로입니다. PathPatternParser는 이 표준을 엄격하게 따르며, 슬래시 유무에 따라 경로를 다르게 해석합니다.
    • SEO (검색 엔진 최적화): Google과 같은 검색 엔진은 .../resource.../resource/를 다른 페이지로 인식할 수 있습니다. PathPatternParser의 엄격한 규칙은 이러한 중복 콘텐츠 문제를 피하고, URL을 하나로 통일하는 모범 사례(Best Practice)를 따르도록 유도합니다.
    • 공식 문서 근거: Spring Framework PathPatternParser의 JavaDoc API 문서(링크)에 따르면, setMatchOptionalTrailingSeparator 기능이 Spring 6.0부터 @Deprecated 되었고, 이 기능의 기본값이 true에서 false로 변경되었습니다. 이는 '슬래시 유무를 엄격하게 구분하여 매칭한다'는 것을 의미합니다.

  • 결과: 클라이언트가 보낸 .../resource/ 요청은 서버 컨트롤러에 정의된 .../resource 패턴과 일치하지 않는 것(false)으로 판단되어, 404 Not Found 에러를 반환하게 된 것입니다.

결론: 버그가 아니라, 프레임워크의 의도된 진화였다

이 문제는 서버 마이그레이션으로 인해 Spring Framework가 더 현대적이고 표준을 지향하는 방식으로 진화하면서 발생한 '의도된 변화'이자 '성장통'이었습니다. 과거의 '관대한' 환경에서는 잠재되어 있던 클라이언트의 비표준적인 URL 요청 방식이, 최신 Spring Boot의 '원칙을 지키는' 환경과 만나면서 비로소 수면 위로 드러난 것입니다.

따라서 가장 올바른 해결책은 서버의 설정을 과거로 되돌려 비표준을 감수하는 것이 아니라, 클라이언트(안드로이드 앱)가 API 명세에 맞는 표준 URL (.../resource 형태로 슬래시 제거)을 보내도록 코드를 수정하는 것입니다.