Reputation: 315
I'm trying to translate an extensive set of routing configuration to the Spring Cloud Gateway Yaml DSL.
One problem I'm running into is (the exceedingly common case) where multiple paths should map to the same route. That is, any incoming URL matching /abc/**
, /def/**
, or /ghi/**
should be routed to some uri http://example.org
(and have the same set of filters, etc. applied).
In the Fluent Java-based routing approach, this can be achieved via the .or().
method eg: r.path("/abc/**").or().path("/def/**").or().path("/fhi/**")...
How can this same functionality be achieved via the YAML-based route config?
Edit: I see in the docs: https://cloud.spring.io/spring-cloud-gateway/single/spring-cloud-gateway.html#gateway-request-predicates-factories
"Multiple Route Predicate Factories can be combined and are combined via logical
and
"
Is there another way to achieve this OR-ing of path predicates via Yaml without declaring multiple routes? Can something be overridden to support this?
Upvotes: 3
Views: 6756
Reputation: 41
You probably have already got the answer. But for the record, I would say you can add multiple paths for the predicates as follows:
spring:
cloud:
gateway:
routes:
- id: instructors_route
uri: lb://INSTRUCTOR-SERVICE/
predicates:
- Path=/api/v1/instructors**,/api/v1/countries**
Upvotes: 4
Reputation: 315
I have found the method that handles the combination of predicates:
RouteDefinitionRouteLocator.java: combinePredicates
:
private AsyncPredicate<ServerWebExchange> combinePredicates(RouteDefinition routeDefinition) {
List<PredicateDefinition> predicates = routeDefinition.getPredicates();
AsyncPredicate<ServerWebExchange> predicate = lookup(routeDefinition, predicates.get(0));
for (PredicateDefinition andPredicate : predicates.subList(1, predicates.size())) {
AsyncPredicate<ServerWebExchange> found = lookup(routeDefinition, andPredicate);
predicate = predicate.and(found);
}
return predicate;
}
Since it is a private method, in order to override this logic with predicate-combining logic that performs the logical disjunction ("OR-ing") of the Path
predicates, an extending class of RouteDefinitionRouteLocator
must re-define all of the methods that lead to the eventual calling of combinePredicates
(which is not the most flexible of routes to take). However, I was able to achieve the functionality I needed by re-implementing the method like so:
private AsyncPredicate<ServerWebExchange> combinePredicates(RouteDefinition routeDefinition) {
//filter out "Path" predicates and place in separate list
List<PredicateDefinition> predicates = routeDefinition.getPredicates();
List<PredicateDefinition> pathPredicates = new ArrayList();
for(PredicateDefinition predicate : predicates){
if (PATH_PREDICATE_NAME.equals(predicate.getName())) {
pathPredicates.add(predicate);
}
}
predicates.removeAll(pathPredicates);
//create an uber predicate out of the "Path" predicates by combining them w/ `or`
AsyncPredicate<ServerWebExchange> pathPredicate = null;
if(pathPredicates.size()>0){
pathPredicate = lookup(routeDefinition, pathPredicates.get(0));
for (PredicateDefinition andPredicate : pathPredicates.subList(1, pathPredicates.size())) {
AsyncPredicate<ServerWebExchange> found = lookup(routeDefinition, andPredicate);
pathPredicate = pathPredicate.or(found);
}
}
//"AND" together the uber path predicate and the rest of the predicates for the route
AsyncPredicate<ServerWebExchange> predicate;
List<PredicateDefinition> predicateSubList;
if(pathPredicate != null) {
predicate = pathPredicate;
predicateSubList = predicates;
} else {
predicate = lookup(routeDefinition, predicates.get(0));
predicateSubList = predicates.subList(1, predicates.size());
}
for (PredicateDefinition andPredicate : predicateSubList) {
AsyncPredicate<ServerWebExchange> found = lookup(routeDefinition, andPredicate);
predicate = predicate.and(found);
}
return predicate;
}
Then, overriding the declared routeDefinitionRouteLocator
RouteLocator
@Bean
config in GatewayAutoConfiguration.java
with this new class enables the new logic to be used.
Upvotes: 0