-
[Spring Cloud Gateway][운영] RewritePath args는 맞는데 default-filters와 globalfilters order가 섞일 때 어느 actuator dump부터 다시 보나백엔드/Spring 2026. 8. 28. 20:17
IT 리서치 노트
[Spring Cloud Gateway][운영] RewritePath args는 맞는데 default-filters와 globalfilters order가 섞일 때 어느 actuator dump부터 다시 보나
Spring Cloud Gateway에서 RewritePath args가 맞는 것까지 확인했는데도 live request path가 예상과 다르면, 다음에는 route 내부 filter만 볼지 공통 filter 레이어까지 볼지부터 갈린다. 2026년 8월 28일 기준 Spring Cloud Gateway 5.0.3 문서를 다시 보면
default-filters, route별combinedfilters, bean-levelglobalfilters, verbose/actuator/gateway/routes는 서로 다른 층이다. 이 글은 그 층이 섞일 때 어느 actuator dump부터 다시 보면 되는지 정리한다.1. 개요
결론부터 말하면 RewritePath args가 이미 맞다면 먼저 route별
combinedfilters, 다음으로 verboseroutes, 그다음default-filters설정, 마지막으로globalfilters순서로 보는 편이 가장 빠르다. default filter는 route에 결합된 공통 layer이고, global filter는 bean-level routing chain이어서 질문이 다르다.앞단으로는 RewritePath와 filter order 글과 target-route snapshot 글이 연결된다. 이번 글은 그 뒤에
default-filters와globalfilters를 같은 증상으로 오해하지 않게 만드는 후속편이다.2. 어디서 실제로 막히는가
현장에서 가장 흔한 실수는
/actuator/gateway/globalfilters만 보고 route-level RewritePath 문제까지 설명하려는 것이다. 그런데 Actuator API 문서는combinedfilters와globalfilters를 분리해 두고, 각각 route-specific chain과 global bean chain을 보여 준다.두 번째 실수는
default-filters를 단순 route YAML의 일부처럼 생각하는 것이다. Default Filters 문서가 말하듯 이 설정은 모든 route에 공통 적용된다. 따라서 특정 route에서만 문제가 보이더라도 실제 chain에는 공통 필터가 이미 결합되어 있을 수 있다.세 번째 실수는 이미 routed 상태를 route filter mismatch로 계속 읽는 것이다. Global Filters 문서는 exchange가 routed로 표시되면 다른 routing filter가 다시 route하지 않는다고 설명한다. 이 경우에는 RewritePath args보다 global routing 흐름을 먼저 봐야 한다.
- 증상: RewritePath 정규식은 맞는데 live path가 여전히 다르다.
- 실패:
globalfilters한 덤프만 보고 route filter order까지 설명한다. - 막힘:
default-filters와 route-specific filters를 같은 층으로 적는다. - 누락:
already routed여부를 따로 남기지 않는다.
같아 보이는 로그 실제 층 먼저 볼 곳 route별 filter order 이상 route-level chain /actuator/gateway/routes/{id}/combinedfilters모든 route에서 공통 이상 default filter layer spring.cloud.gateway.default-filtersroute 자체가 다시 안 탄다 global routing layer /actuator/gateway/globalfilters와 routed 상태3. 실무에서 적용하는 순서
가장 짧은 triage는 네 단계다. 먼저
combinedfilters로 해당 route의 실제 결합 순서를 본다. 다음으로 verboseroutes에서 human-readable filter 설명을 읽는다. 세 번째로default-filters설정을 대조한다. 마지막으로globalfilters와 routed 상태를 본다.- route별
combinedfilters에서 실제 결합 순서를 확인한다. - verbose
routes로 filter 설명과 route order를 읽는다. default-filters설정으로 공통 layer를 대조한다.globalfilters와already routed여부를 마지막에 본다.
실제로는 actuator endpoint를 호출해 응답을 조회하고, route id를 입력해 combinedfilters를 확인하고, application 설정 파일과 로그 파일을 나란히 열고, globalfilters 응답을 저장한 뒤, route 응답과 비교하는 순서가 가장 덜 꼬인다. 이 절차를 메모에 남겨 두면 콘솔 조회와 설정 비교를 다시 실행하기도 쉽다.
이 순서를 고정하면 route definition 문제와 bean-level routing 문제를 같은 incident 메모에 섞지 않게 된다. 특히 route YAML에서 RewritePath와 PrefixPath가 맞아 보이는데 live path가 계속 어긋날 때, 공통 default filter를 먼저 놓치면 이후 로그 비교가 계속 길어진다.
같은 Spring branch에서 더 넓은 맥락이 필요하면 Java DSL route source 점검 글과 route-id-prefix와 RewritePath 기본값 글을 함께 보면 route source와 runtime chain이 더 잘 연결된다.
4. 공식 문서와 예시 화면으로 확인하기
첫 자료는 2026년 8월 28일 기준 Spring Cloud Gateway RewritePath 문서다. 여기서는
regexp와replacement가 맞는지 확인하는 단계가 기본 출발점이다.이번 글은 이 단계가 이미 맞다는 가정에서 출발한다. 그래서 다음 막힘은 RewritePath 자체보다 filter chain 어디에서 그 결과가 섞였는지 보는 일이다.
두 번째 자료는 Default Filters 문서다. Spring Cloud Gateway는
spring.cloud.gateway.default-filters를 모든 route에 적용하는 공통 필터 레이어로 설명한다.즉 route YAML에서 RewritePath args가 맞아도, 공통 default filter가 앞뒤로 끼어들면 live filter chain 해석이 달라질 수 있다. route 정의 한 장만 보면 놓치기 쉽다.
세 번째 자료는 Actuator API 문서의 endpoint 목록이다. 여기서
/actuator/gateway/routes/{id}/combinedfilters와/actuator/gateway/globalfilters가 서로 다른 dump라는 점을 먼저 구분해야 한다.이 구분이 없으면 공통 default filter와 bean-level global filter를 같은 표에서 섞어 읽게 된다. incident note가 길어지는 이유가 대부분 여기서 시작된다.
네 번째 자료는 Global Filters 문서다. Spring Cloud Gateway는 exchange가 이미 routed로 표시되면 다른 routing filter가 다시 route하지 않는다고 설명한다.
그래서 global filter order 문제는 route-level RewritePath와는 다른 층이다. 같은 request path mismatch라도 이미 routed 상태면 route filter보다 global routing 흐름을 먼저 봐야 한다.
실무에서는 어떤 actuator dump를 어떤 순서로 열지 먼저 고정해 두는 편이 빠르다. 아래 표는 RewritePath args가 이미 맞다는 가정에서 보는 최소 순서다.
이미 RewritePath와 filter order 글이 route-level mismatch를 다뤘다면, 이번 표는 그 뒤에 공통 레이어를 어떻게 더 좁힐지 정리한 후속편이다.
마지막 자료는 incident 로그 예시다. route-level chain과 global chain을 한 화면에 합치지 말고, 최소한 두 블록으로 분리해 저장하는 편이 좋다.
같은 branch에서는 target-route snapshot 글과 handler-mapping.order 분리 글을 같이 두면 더 자연스럽다.
5. 주의사항과 리스크
첫 번째 리스크는
globalfilters를 route-level 실행 순서로 오해하는 것이다. 두 번째 리스크는default-filters를 route YAML diff에서 빠뜨리는 것이다. 세 번째 리스크는already routed상태를 남기지 않아 global routing short-circuit를 놓치는 것이다.운영 메모에는 최소한
route_id,combinedfilters,default-filters,globalfilters,already routed다섯 값을 따로 남기는 편이 좋다. 이 다섯 줄이 있으면 route 정의 문제와 global routing 문제를 훨씬 빨리 자를 수 있다.- default filter는 route 공통 레이어다.
- global filter는 bean-level routing 체인이다.
- 두 층은 같은 증상처럼 보여도 읽는 dump가 다르다.
6. 결론
RewritePath args가 맞다면 다음 질문은 route 내부냐, 공통 default layer냐, global routing layer냐를 가르는 일이다. 그때는
combinedfilters, verboseroutes,default-filters,globalfilters순서를 고정해 두는 편이 가장 실용적이다.이 후속편을 기존 RewritePath 글에 연결해 두면 Spring Cloud Gateway branch가 handler-mapping, target snapshot, route filter, 공통 filter 순서로 자연스럽게 이어진다.
레이어 전체를 한 번에 비교하는 진입 글이 필요하면 새 허브 글인 route filter와 default-filters와 GlobalFilter 비교 글로 이어 두면 route dump와 bean dump를 같은 맥락으로 설명하기 쉽다.
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/gatewayfilter-factories/default-filters.html
- https://docs.spring.io/spring-cloud-gateway/reference/spring-cloud-gateway-server-webflux/global-filters.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
'백엔드 > Spring' 카테고리의 다른 글