Spring Cloud Gateway路由定位器与发现定位器技术咨询
Spring Cloud Gateway Discovery Locator 相关问题解答
场景说明
我有一个启用了Discovery Locator的Spring Cloud Gateway应用,基于Eureka的DiscoveryClient自动创建路由,配置如下:
spring: cloud: gateway: discovery: locator: enabled: true lowerCaseServiceId: true filters: - name: Retry args: retries: 10
同时通过RouteLocatorBuilder定义了一条路由:
@Bean public RouteLocator routeLocator(RouteLocatorBuilder routeLocatorBuilder) { return routeLocatorBuilder.routes() .route(r -> r .path("/test/**") .filters(filters -> filters.addResponseHeader("testHeaderName", "testHeaderValue")) .uri("lb://test-service")) .build(); }
问题1:如何将discovery.locator配置的过滤器添加到RouteLocatorBuilder定义的路由中?
可以实现,有两种可行方案:
方案1:手动复用配置中的过滤器定义
通过注入GatewayProperties读取Discovery Locator配置的过滤器列表,在自定义路由中直接添加这些过滤器:
@Bean public RouteLocator routeLocator(RouteLocatorBuilder routeLocatorBuilder, GatewayProperties gatewayProperties) { // 获取discovery locator配置的过滤器集合 List<FilterDefinition> discoveryFilters = gatewayProperties.getDiscovery().getLocator().getFilters(); return routeLocatorBuilder.routes() .route(r -> r .path("/test/**") .filters(filters -> { // 添加自定义响应头过滤器 filters.addResponseHeader("testHeaderName", "testHeaderValue"); // 批量添加discovery locator配置的过滤器 discoveryFilters.forEach(filters::filter); return filters; }) .uri("lb://test-service")) .build(); }
方案2:自定义全局过滤器(自动适配特定路由)
如果希望Discovery Locator的过滤器自动应用到所有自定义的lb://类型路由,可以编写全局过滤器,判断路由类型后注入Retry过滤器:
@Component public class DiscoveryLocatorFilterAdder implements GlobalFilter, Ordered { private final RetryGatewayFilterFactory retryFactory; public DiscoveryLocatorFilterAdder(RetryGatewayFilterFactory retryFactory) { this.retryFactory = retryFactory; } @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR); // 仅对lb协议的自定义路由生效 if (route != null && route.getUri().getScheme().equals("lb")) { // 复用配置中的重试参数创建过滤器 GatewayFilter retryFilter = retryFactory.apply(c -> c.setRetries(10)); return retryFilter.filter(exchange, chain); } return chain.filter(exchange); } @Override public int getOrder() { // 设置执行顺序,确保在自定义路由过滤器之前生效 return -1; } }
问题2:启用discovery.locator时,能否避免在路由URI中显式指定服务ID?
不行。
Discovery Locator自动创建路由的逻辑是基于服务ID生成固定路径规则(比如/test-service/**自动映射到lb://test-service),但自定义路由是你手动定义的规则,Gateway无法自动推断/test/**应该转发到哪个注册服务——如果不明确指定lb://test-service,网关没有依据定位目标服务实例。
如果想避免硬编码服务ID,可以通过配置文件解耦:
# application.yml app: target-service: test-service
然后在代码中注入配置值:
@Value("${app.target-service}") private String targetService; @Bean public RouteLocator routeLocator(RouteLocatorBuilder routeLocatorBuilder) { return routeLocatorBuilder.routes() .route(r -> r .path("/test/**") .filters(filters -> filters.addResponseHeader("testHeaderName", "testHeaderValue")) .uri("lb://" + targetService)) .build(); }
这种方式可以通过配置文件灵活修改目标服务,无需改动代码。
内容的提问来源于stack exchange,提问作者Anton Skripin
相关产品推荐
相关产品推荐

