diff --git a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/discovery/DiscoveryClientRouteDefinitionLocator.java b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/discovery/DiscoveryClientRouteDefinitionLocator.java index b5f86440..2879c5ab 100644 --- a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/discovery/DiscoveryClientRouteDefinitionLocator.java +++ b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/discovery/DiscoveryClientRouteDefinitionLocator.java @@ -28,6 +28,7 @@ import org.springframework.cloud.gateway.filter.FilterDefinition; import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition; import org.springframework.cloud.gateway.route.RouteDefinition; import org.springframework.cloud.gateway.route.RouteDefinitionLocator; +import org.springframework.core.style.ToStringCreator; import org.springframework.expression.Expression; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.SimpleEvaluationContext; @@ -84,11 +85,13 @@ public class DiscoveryClientRouteDefinitionLocator implements RouteDefinitionLoc String uri = urlExpr.getValue(evalCtxt, instance, String.class); routeDefinition.setUri(URI.create(uri)); + final ServiceInstance instanceForEval = new DelegatingServiceInstance(instance, properties); + for (PredicateDefinition original : this.properties.getPredicates()) { PredicateDefinition predicate = new PredicateDefinition(); predicate.setName(original.getName()); for (Map.Entry entry : original.getArgs().entrySet()) { - String value = getValueFromExpr(evalCtxt, parser, instance, entry); + String value = getValueFromExpr(evalCtxt, parser, instanceForEval, entry); predicate.addArg(entry.getKey(), value); } routeDefinition.getPredicates().add(predicate); @@ -98,7 +101,7 @@ public class DiscoveryClientRouteDefinitionLocator implements RouteDefinitionLoc FilterDefinition filter = new FilterDefinition(); filter.setName(original.getName()); for (Map.Entry entry : original.getArgs().entrySet()) { - String value = getValueFromExpr(evalCtxt, parser, instance, entry); + String value = getValueFromExpr(evalCtxt, parser, instanceForEval, entry); filter.addArg(entry.getKey(), value); } routeDefinition.getFilters().add(filter); @@ -112,4 +115,61 @@ public class DiscoveryClientRouteDefinitionLocator implements RouteDefinitionLoc Expression valueExpr = parser.parseExpression(entry.getValue()); return valueExpr.getValue(evalCtxt, instance, String.class); } + + private static class DelegatingServiceInstance implements ServiceInstance { + + final ServiceInstance delegate; + private final DiscoveryLocatorProperties properties; + + private DelegatingServiceInstance(ServiceInstance delegate, DiscoveryLocatorProperties properties) { + this.delegate = delegate; + this.properties = properties; + } + + @Override + public String getServiceId() { + if (properties.isLowerCaseServiceId()) { + return delegate.getServiceId().toLowerCase(); + } + return delegate.getServiceId(); + } + + @Override + public String getHost() { + return delegate.getHost(); + } + + @Override + public int getPort() { + return delegate.getPort(); + } + + @Override + public boolean isSecure() { + return delegate.isSecure(); + } + + @Override + public URI getUri() { + return delegate.getUri(); + } + + @Override + public Map getMetadata() { + return delegate.getMetadata(); + } + + @Override + public String getScheme() { + return delegate.getScheme(); + } + + @Override + public String toString() { + return new ToStringCreator(this) + .append("delegate", delegate) + .append("properties", properties) + .toString(); + } + } } diff --git a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/discovery/DiscoveryLocatorProperties.java b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/discovery/DiscoveryLocatorProperties.java index 8de0eacb..287b65a1 100644 --- a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/discovery/DiscoveryLocatorProperties.java +++ b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/discovery/DiscoveryLocatorProperties.java @@ -47,6 +47,13 @@ public class DiscoveryLocatorProperties { /** SpEL expression that create the uri for each route, defaults to: 'lb://'+serviceId */ private String urlExpression = "'lb://'+serviceId"; + /** + * Option to lower case serviceId in predicates and filters, defaults to false. + * Useful with eureka when it automatically uppercases serviceId. + * so MYSERIVCE, would match /myservice/** + */ + private boolean lowerCaseServiceId = false; + private List predicates = new ArrayList<>(); private List filters = new ArrayList<>(); @@ -83,6 +90,14 @@ public class DiscoveryLocatorProperties { this.urlExpression = urlExpression; } + public boolean isLowerCaseServiceId() { + return lowerCaseServiceId; + } + + public void setLowerCaseServiceId(boolean lowerCaseServiceId) { + this.lowerCaseServiceId = lowerCaseServiceId; + } + public List getPredicates() { return predicates; } @@ -106,6 +121,7 @@ public class DiscoveryLocatorProperties { .append("routeIdPrefix", routeIdPrefix) .append("includeExpression", includeExpression) .append("urlExpression", urlExpression) + .append("lowerCaseServiceId", lowerCaseServiceId) .append("predicates", predicates) .append("filters", filters) .toString(); diff --git a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/discovery/DiscoveryClientRouteDefinitionLocatorTests.java b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/discovery/DiscoveryClientRouteDefinitionLocatorTests.java index 6a0636ad..3a3f0f13 100644 --- a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/discovery/DiscoveryClientRouteDefinitionLocatorTests.java +++ b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/discovery/DiscoveryClientRouteDefinitionLocatorTests.java @@ -49,11 +49,12 @@ import static org.springframework.cloud.gateway.handler.predicate.RoutePredicate properties = {"spring.cloud.gateway.discovery.locator.enabled=true", "spring.cloud.gateway.discovery.locator.route-id-prefix=testedge_", "spring.cloud.gateway.discovery.locator.include-expression=metadata['edge'] == 'true'", - "spring.cloud.gateway.discovery.locator.predicates[0].name=Path", + "spring.cloud.gateway.discovery.locator.lower-case-service-id=true", + /*"spring.cloud.gateway.discovery.locator.predicates[0].name=Path", "spring.cloud.gateway.discovery.locator.predicates[0].args[pattern]='/'+serviceId.toLowerCase()+'/**'", "spring.cloud.gateway.discovery.locator.filters[0].name=RewritePath", "spring.cloud.gateway.discovery.locator.filters[0].args[regexp]='/' + serviceId.toLowerCase() + '/(?.*)'", - "spring.cloud.gateway.discovery.locator.filters[0].args[replacement]='/$\\\\{remaining}'", + "spring.cloud.gateway.discovery.locator.filters[0].args[replacement]='/$\\\\{remaining}'",*/ }) public class DiscoveryClientRouteDefinitionLocatorTests { @@ -84,7 +85,7 @@ public class DiscoveryClientRouteDefinitionLocatorTests { assertThat(filter.getName()).isEqualTo("RewritePath"); assertThat(filter.getArgs()).hasSize(2) .containsEntry(REGEXP_KEY, "/service1/(?.*)") - .containsEntry(REPLACEMENT_KEY, "/$\\{remaining}"); + .containsEntry(REPLACEMENT_KEY, "/${remaining}"); } @SpringBootConfiguration