Spring Cloud Gateway路由上下文路径失效求助
你遇到的问题其实是Spring Cloud Gateway的一个常见特性——它的路由匹配逻辑是基于原始请求的完整路径(去掉端口后的部分),而不是经过Servlet容器处理过的、去掉context-path之后的路径。也就是说,当你配置了context-path: /gb-integration,Gateway在匹配路由时,仍然会看到完整的请求路径/gb-integration/sbl/xxx,但你的路由只匹配/sbl/**,所以只有直接访问localhost:4177/sbl/**才会命中路由。
下面给你两种可行的解决方案:
方案1:显式在路由Path中添加上下文路径
直接修改路由的path规则,把上下文路径包含进去,同时调整rewritePath的规则,确保正确转发到目标服务:
@Bean public RouteLocator routeLocator(RouteLocatorBuilder builder) { final String sbl = "http://localhost:4178"; return builder.routes() //gb-sbl-rest .route("sbl", r -> r .path("/gb-integration/sbl/**") // 加上上下文路径 .filters(f -> f.rewritePath("/gb-integration/sbl/(?<segment>.*)", "/gb-sbl/${segment}")) // 调整重写规则 .uri(sbl)) .build(); }
配置完成后,访问localhost:4177/gb-integration/sbl/**就能正常匹配路由并转发了。
方案2:动态获取上下文路径(更灵活)
如果后续可能需要修改上下文路径,不想手动逐个修改路由,可以注入ServerProperties来动态获取配置的context-path,自动拼接成路由规则:
import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.context.annotation.Bean; import org.springframework.cloud.gateway.route.RouteLocator; import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; import org.springframework.beans.factory.annotation.Autowired; @Autowired private ServerProperties serverProperties; @Bean public RouteLocator routeLocator(RouteLocatorBuilder builder) { final String sbl = "http://localhost:4178"; String contextPath = serverProperties.getServlet().getContextPath(); // 去掉开头的斜杠,避免拼接后出现重复斜杠 if (contextPath.startsWith("/")) { contextPath = contextPath.substring(1); } // 拼接路由匹配路径 String pathPattern = contextPath + "/sbl/**"; return builder.routes() .route("sbl", r -> r .path(pathPattern) .filters(f -> f.rewritePath("/" + contextPath + "/sbl/(?<segment>.*)", "/gb-sbl/${segment}")) .uri(sbl)) .build(); }
这种方式的好处是,只要修改application.yml中的context-path,路由规则会自动适配,不需要改动代码。
补充:为什么原来的配置不生效?
Spring Cloud Gateway基于WebFlux实现,它的请求处理流程是在Servlet容器(比如Tomcat)处理context-path之前就进行路由匹配的。也就是说,当请求localhost:4177/gb-integration/sbl/xxx到达Gateway时,Gateway看到的完整路径是/gb-integration/sbl/xxx,而你的路由只匹配/sbl/**,所以自然不会命中。只有当请求路径是/sbl/xxx时,才会匹配到你定义的路由。
内容的提问来源于stack exchange,提问作者Shervin Asgari

