-
[Spring Cloud Gateway][운영] RewritePath는 맞는데 filter order와 actuator route dump가 어긋날 때 어떤 로그부터 비교하나백엔드/Spring 2026. 8. 28. 09:16
IT 리서치 노트
[Spring Cloud Gateway][운영] RewritePath는 맞는데 filter order와 actuator route dump가 어긋날 때 어떤 로그부터 비교하나
Spring Cloud Gateway에서 target route snapshot까지 확인했는데도 downstream path가 기대와 다르면 그다음에는 RewritePath와 filter order를 따로 봐야 한다. 2026년 8월 28일 KST 기준 Spring 공식 문서를 다시 보면 RewritePath는 regexp와 replacement로 정의되고, actuator는 route detail과 combinedfilters를 따로 보여 주며, handler-mapping.order는 그보다 바깥의 진입 순서다. 이 글은 RewritePath는 맞는데 filter order와 actuator route dump가 어긋날 때 어떤 로그부터 비교해야 짧게 원인을 분리할 수 있는지 정리한다.
1. 개요
결론부터 말하면 RewritePath drift는
route dump의 RewritePath args와combinedfilters의 실제 순서를 같은 시각으로 먼저 비교하는 편이 맞다. route detail에 RewritePath가 있다고 해도 regexp, replacement, filter chain order가 다르면 downstream path 결과는 달라질 수 있다.같은 branch를 이어 읽는다면 routes.count parity 뒤 target snapshot 글과 handler-mapping.order 분리 글이 앞단이다. 이번 글은 그 뒤에서 filter chain 쪽만 한 단계 더 좁힌다.
2. 어디서 실제로 막히는가
현장에서 흔한 착각은 route dump에 RewritePath가 보이면 rewrite 설정은 맞다고 생각하는 것이다. 그런데 공식 문서가 보여 주듯 RewritePath는 regexp와 replacement 두 값으로 구성되고, actuator는 route detail과 combinedfilters를 अलग endpoint로 보여 준다. 즉 이름만 같고 파라미터가 다르거나, 파라미터는 같은데 실제 order가 다른 경우가 충분히 생긴다.
두 번째 실패는 handler-mapping.order를 이미 확인한 뒤에도 order 문제를 다시 그 값 하나로 설명하는 것이다. handler-mapping.order는 RoutePredicateHandlerMapping 층위의 순서이고, combinedfilters는 개별 route filter chain 층위다. 둘을 같은 order로 취급하면 진입 문제와 rewrite 체인 문제를 섞는다.
세 번째 실패는 route detail과 combinedfilters를 다른 시점에 모으는 것이다. 배포 직후 한 번은 old route dump, 다음 한 번은 new combinedfilters를 보면 같은 route라도 서로 다른 버전을 비교하게 된다. RewritePath drift는 snapshot 시각이 곧 정확도다.
- 증상: RewritePath가 보이는데도 downstream path나 proxy 결과가 기대와 다르다.
- 실패: filter 이름 존재만 확인하고 regexp와 replacement를 기록하지 않는다.
- 막힘: combinedfilters를 안 보고 order 문제를 handler-mapping.order로만 설명한다.
- 누락: route dump와 combinedfilters 수집 시각을 함께 남기지 않는다.
같아 보여도 다른 층위 실제 의미 왜 다시 분리하나 handler-mapping.order 진입 handler 순서 RewritePath 체인과는 다른 단계이기 때문 route detail filters 선언된 filter 목록과 args 파라미터 drift를 보기 위해 combinedfilters 실제 적용 순서 체인 실행 결과를 설명하기 위해 3. 실무에서 적용하는 순서
가장 짧은 점검 순서는 다섯 단계다. 먼저 target route detail을 조회한다. 다음으로 같은 route id의 combinedfilters를 조회한다. 세 번째로 RewritePath의 regexp와 replacement를 추출한다. 네 번째로 filter order와 snapshot 시각을 붙인다. 마지막으로 mappings를 열어 진입 층위와 route filter 층위를 섞지 않았는지 확인한다.
- route detail에서 RewritePath args를 먼저 저장한다.
- 같은 route id의 combinedfilters를 바로 이어서 조회한다.
- regexp와 replacement가 기대와 같은지 확인한다.
- filter order와 snapshot 시각을 붙인다.
- mappings로 진입 층위 문제와 분리한다.
실제로는 운영자가 actuator route detail을 조회하고, combinedfilters endpoint를 실행하고, regex와 replacement를 파일에 복사하고, order를 메모에 입력하고, mappings 응답을 같은 시각으로 저장하는 순서를 고정하면 된다. 이 동작을 빼먹으면 route 이름과 filter 이름만 보고도 충분하다고 착각하기 쉽다.
관련 글로는 target snapshot 글, route-id-prefix와 RewritePath 기본값 글, Java DSL route source 글을 같이 두면 다음 triage가 더 짧다.
4. 공식 문서와 예시 화면으로 확인하기
첫 자료는 RewritePath GatewayFilter 문서다. 이 화면에서는 rewrite가 단순 on/off가 아니라 regexp와 replacement 두 값으로 구성된다는 사실을 먼저 확인해야 한다.
즉 `RewritePath가 있다`는 사실만으로는 부족하다. 어느 regex가 들어갔는지, replacement가 무엇인지, 그리고 그 filter가 실제 체인에서 어느 순서로 적용되는지를 같이 남겨야 한다.
두 번째 자료는 actuator API 문서다. 여기서는 route별 combinedfilters endpoint가 따로 노출된다는 점을 볼 수 있다.
이 endpoint가 중요한 이유는 route dump의 filter 이름 목록만으로는 실제 order를 설명하기 어렵기 때문이다. RewritePath가 보이더라도 앞뒤 filter와의 상대 순서를 봐야 downstream path 결과를 해석할 수 있다.
세 번째 자료는 appendix의 handler-mapping.order 항목이다. 이전 글에서 분리했듯 이 값은 route detail 안의 filter order와 다른 층위다.
그래서 handler-mapping.order를 이미 확인했다면 다음 단계는 다시 그 값을 만지는 것이 아니라 route dump와 combinedfilters를 비교하는 일이다. 같은 order라는 단어라도 층위가 다르다.
실무에서는 route dump와 combinedfilters를 같은 시각에 비교하는 표가 필요하다. 아래 표는 RewritePath가 맞아 보이는데도 동작이 다른 경우에 먼저 붙일 로그 열을 정리한 것이다.
같은 Spring branch에서는 routes.count parity 뒤 target snapshot 글이 앞단이고, 이번 표는 그 target snapshot 안에서 RewritePath와 filter order만 다시 좁히는 후속편이다.
마지막 자료는 실제 조회 순서 예시다. route dump만 열어 놓고 combinedfilters를 안 보면 RewritePath 파라미터는 맞는데 실행 순서가 다른 경우를 놓치기 쉽다.
이 순서만 지켜도 route count 단계, handler-mapping 단계, filter chain 단계가 섞이지 않는다. 관련 글로는 handler-mapping.order 분리 글과 Java DSL route source 점검 글을 같이 두면 좋다.
5. 주의사항과 리스크
첫 번째 리스크는 RewritePath 이름만 보고 인자 비교를 생략하는 것이다. 두 번째 리스크는 combinedfilters를 안 보고 route dump filters 배열만 보는 것이다. 세 번째 리스크는 서로 다른 배포 시각의 route dump와 combinedfilters를 비교하는 것이다.
운영 전에 최소한
target_route_id,rewrite_regexp,rewrite_replacement,combinedfilters_order,snapshot_at은 남기는 편이 좋다. 이 다섯 값이 없으면 filter chain drift를 다시 좁히기 어렵다.- RewritePath 존재 여부와 RewritePath 적용 순서는 다른 문제다.
- combinedfilters는 route detail의 보조가 아니라 별도 증거다.
- 같은 시각 snapshot이 아니면 route diff 품질이 떨어진다.
6. 결론
Spring Cloud Gateway에서 RewritePath가 맞아 보이는데도 동작이 다르면, 다음 단계는 route dump의 args와 combinedfilters의 order를 같은 시각으로 다시 붙이는 일이다. 이렇게 나누면 handler-mapping.order와 route filter chain을 섞지 않고 실제 path rewrite 차이를 더 빨리 설명할 수 있다.
같은 흐름에서 route dump는 정상이지만 default-filters와 globalfilters 순서가 따로 흔들리는지 확인하려면 RewritePath args는 맞는데 default-filters와 globalfilters order가 섞일 때 어느 actuator dump부터 다시 보나를 이어서 보면 actuator 증거를 더 단단하게 묶을 수 있다.
- RewritePath args와 combinedfilters order를 같이 본다.
- handler-mapping.order는 진입 층위로만 남긴다.
- route dump와 combinedfilters 수집 시각을 고정한다.
7. 참고 링크
- https://docs.spring.io/spring-cloud-gateway/reference/spring-cloud-gateway-server-webflux/gatewayfilter-factories/rewritepath-factory.html
- https://docs.spring.io/spring-cloud-gateway/reference/spring-cloud-gateway-server-webflux/actuator-api.html
- https://docs.spring.io/spring-cloud-gateway/reference/appendix.html
- https://docs.spring.io/spring-boot/api/rest/actuator/mappings.html
'백엔드 > Spring' 카테고리의 다른 글