如何在Spring Cloud Gateway中统一去除所有路由的断言路径前缀?
Spring Cloud Gateway 全局自动去除路由前缀方案
Spring Cloud Gateway 4.x 没有原生提供类似 Zuul 1.x 中自动去除路由前缀的全局配置,但可以通过自定义全局过滤器实现相同效果,自动适配不同路由的前缀段数。
自定义全局过滤器实现自动StripPrefix
这个过滤器会自动识别当前路由的Path断言模式,计算需要去除的前缀段数,无需在每个路由中单独配置StripPrefix过滤器。
实现代码
import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.cloud.gateway.route.Route; import org.springframework.cloud.gateway.route.builder.PathRoutePredicateFactory; import org.springframework.core.Ordered; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; import java.util.Optional; @Component public class AutoStripPrefixGlobalFilter implements GlobalFilter, Ordered { private static final String GATEWAY_ROUTE_ATTR = "org.springframework.cloud.gateway.support.ServerWebExchangeUtils.gatewayRoute"; @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { Route currentRoute = exchange.getAttribute(GATEWAY_ROUTE_ATTR); if (currentRoute == null) { return chain.filter(exchange); } // 提取路由的Path断言规则 Optional<PathRoutePredicateFactory.PathSpec> pathSpec = currentRoute.getPredicate() .getArgs().values().stream() .filter(arg -> arg instanceof PathRoutePredicateFactory.PathSpec) .map(arg -> (PathRoutePredicateFactory.PathSpec) arg) .findFirst(); if (pathSpec.isPresent()) { String pattern = pathSpec.get().getPattern(); // 移除断言末尾的/**,计算前缀段数 String prefix = pattern.replace("/**", ""); int segmentCount = prefix.isEmpty() ? 0 : prefix.split("/").length - 1; if (segmentCount > 0) { String originalPath = exchange.getRequest().getPath().value(); String[] pathSegments = originalPath.split("/"); // 拼接去除前缀后的新路径 StringBuilder newPath = new StringBuilder(); for (int i = segmentCount + 1; i < pathSegments.length; i++) { newPath.append("/").append(pathSegments[i]); } if (newPath.length() == 0) { newPath.append("/"); } // 修改请求路径 exchange.getRequest().mutate().path(newPath.toString()).build(); return chain.filter(exchange.mutate().request(exchange.getRequest()).build()); } } return chain.filter(exchange); } @Override public int getOrder() { // 设置优先级,确保在其他路径处理过滤器前执行 return -1; } }
工作原理
- 从请求上下文获取当前匹配的路由信息
- 解析路由的Path断言(比如
/api/example/**),移除末尾的/**后计算前缀的路径段数(这里是2段) - 截取原始请求路径,去除对应段数的前缀,生成新的请求路径
- 修改请求上下文的路径后,继续执行过滤器链
替代方案:路由配置层面统一处理(无需代码)
如果不想编写自定义过滤器,可以在每条路由中使用RewritePath过滤器,通过变量统一配置:
spring: cloud: gateway: routes: - id: example_route uri: https://samplehost.com:12345 predicates: - Path=/api/example/** filters: - RewritePath=/api/example/(?<remaining>.*), /${remaining} - id: another_route uri: https://anotherhost.com predicates: - Path=/example/** filters: - RewritePath=/example/(?<remaining>.*), /${remaining}
但这种方式需要为30多条路由逐一配置,适合路由数量较少的场景。
内容的提问来源于stack exchange,提问作者Deepak Chhetri
相关产品推荐
相关产品推荐

