Skip to content

Commit 920d2ab

Browse files
committed
Fix Bug : Spring Cloud Gateway Setting Spring.webflux.base-path All Path Predicates Return 404 Results
Fix Bug : Spring Cloud Gateway Setting Spring.webflux.base-path All Path Predicates Return 404 Results Fix Bug : Spring Cloud Gateway Setting Spring.webflux.base-path All Path Predicates Return 404 Results Fix Bug : Spring Cloud Gateway Setting Spring.webflux.base-path All Path Predicates Return 404 Results
1 parent 9073d3e commit 920d2ab

File tree

6 files changed

+101
-18
lines changed

6 files changed

+101
-18
lines changed

spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
import org.apache.commons.logging.Log;
2929
import org.apache.commons.logging.LogFactory;
30+
import org.springframework.boot.autoconfigure.web.reactive.WebFluxProperties;
3031
import reactor.core.publisher.Flux;
3132
import reactor.netty.http.client.HttpClient;
3233
import reactor.netty.http.client.WebsocketClientSpec;
@@ -452,8 +453,8 @@ public MethodRoutePredicateFactory methodRoutePredicateFactory() {
452453

453454
@Bean
454455
@ConditionalOnEnabledPredicate
455-
public PathRoutePredicateFactory pathRoutePredicateFactory() {
456-
return new PathRoutePredicateFactory();
456+
public PathRoutePredicateFactory pathRoutePredicateFactory(WebFluxProperties webFluxProperties) {
457+
return new PathRoutePredicateFactory(webFluxProperties);
457458
}
458459

459460
@Bean

spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicateFactory.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@
2424
import org.apache.commons.logging.Log;
2525
import org.apache.commons.logging.LogFactory;
2626

27+
import org.springframework.boot.autoconfigure.web.reactive.WebFluxProperties;
2728
import org.springframework.core.style.ToStringCreator;
2829
import org.springframework.http.server.PathContainer;
30+
import org.springframework.util.StringUtils;
2931
import org.springframework.validation.annotation.Validated;
3032
import org.springframework.web.server.ServerWebExchange;
3133
import org.springframework.web.util.pattern.PathPattern;
@@ -42,6 +44,7 @@
4244
/**
4345
* @author Spencer Gibb
4446
* @author Dhawal Kapil
47+
* @author Guo FuYiNan
4548
*/
4649
public class PathRoutePredicateFactory extends AbstractRoutePredicateFactory<PathRoutePredicateFactory.Config> {
4750

@@ -51,8 +54,11 @@ public class PathRoutePredicateFactory extends AbstractRoutePredicateFactory<Pat
5154

5255
private PathPatternParser pathPatternParser = new PathPatternParser();
5356

54-
public PathRoutePredicateFactory() {
57+
private final WebFluxProperties webFluxProperties;
58+
59+
public PathRoutePredicateFactory(WebFluxProperties webFluxProperties) {
5560
super(Config.class);
61+
this.webFluxProperties = webFluxProperties;
5662
}
5763

5864
private static void traceMatch(String prefix, Object desired, Object actual, boolean match) {
@@ -83,7 +89,13 @@ public Predicate<ServerWebExchange> apply(Config config) {
8389
synchronized (this.pathPatternParser) {
8490
pathPatternParser.setMatchOptionalTrailingSeparator(config.isMatchTrailingSlash());
8591
config.getPatterns().forEach(pattern -> {
86-
PathPattern pathPattern = this.pathPatternParser.parse(pattern);
92+
String basePath = webFluxProperties.getBasePath();
93+
if (StringUtils.hasText(basePath)) {
94+
if (pattern.length() > 1 && !pattern.startsWith("/")) {
95+
basePath += ("/");
96+
}
97+
}
98+
PathPattern pathPattern = this.pathPatternParser.parse(basePath + pattern);
8799
pathPatterns.add(pathPattern);
88100
});
89101
}
@@ -114,8 +126,7 @@ public boolean test(ServerWebExchange exchange) {
114126
exchange.getAttributes().put(GATEWAY_PREDICATE_MATCHED_PATH_ROUTE_ID_ATTR, routeId);
115127
}
116128
return true;
117-
}
118-
else {
129+
} else {
119130
traceMatch("Pattern", config.getPatterns(), path, false);
120131
return false;
121132
}

spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/GatewayPredicateVisitorTests.java

Lines changed: 74 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,40 @@
1616

1717
package org.springframework.cloud.gateway.handler.predicate;
1818

19-
import java.util.ArrayList;
20-
import java.util.function.Predicate;
21-
2219
import org.junit.jupiter.api.Test;
23-
20+
import org.mockito.ArgumentCaptor;
21+
import org.springframework.boot.autoconfigure.web.reactive.WebFluxProperties;
22+
import org.springframework.cloud.gateway.filter.GatewayFilter;
23+
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
24+
import org.springframework.cloud.gateway.filter.factory.StripPrefixGatewayFilterFactory;
2425
import org.springframework.cloud.gateway.handler.AsyncPredicate;
2526
import org.springframework.cloud.gateway.route.Route;
27+
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
28+
import org.springframework.mock.web.server.MockServerWebExchange;
2629
import org.springframework.web.server.ServerWebExchange;
30+
import reactor.core.publisher.Mono;
31+
32+
import java.net.URI;
33+
import java.util.ArrayList;
34+
import java.util.LinkedHashSet;
35+
import java.util.List;
36+
import java.util.function.Predicate;
2737

2838
import static org.assertj.core.api.Assertions.assertThat;
39+
import static org.mockito.Mockito.mock;
40+
import static org.mockito.Mockito.when;
41+
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR;
42+
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR;
2943

3044
/**
3145
* @author Spencer Gibb
46+
* @author Guo FuYiNan
3247
*/
3348
public class GatewayPredicateVisitorTests {
3449

3550
@Test
3651
public void asyncPredicateVisitVisitsEachNode() {
37-
PathRoutePredicateFactory pathRoutePredicateFactory = new PathRoutePredicateFactory();
52+
PathRoutePredicateFactory pathRoutePredicateFactory = new PathRoutePredicateFactory(new WebFluxProperties());
3853
HostRoutePredicateFactory hostRoutePredicateFactory = new HostRoutePredicateFactory();
3954
ReadBodyRoutePredicateFactory readBodyRoutePredicateFactory1 = new ReadBodyRoutePredicateFactory();
4055
ReadBodyRoutePredicateFactory readBodyRoutePredicateFactory2 = new ReadBodyRoutePredicateFactory();
@@ -55,7 +70,7 @@ public void asyncPredicateVisitVisitsEachNode() {
5570

5671
@Test
5772
public void predicateVisitVisitsEachNode() {
58-
PathRoutePredicateFactory pathRoutePredicateFactory = new PathRoutePredicateFactory();
73+
PathRoutePredicateFactory pathRoutePredicateFactory = new PathRoutePredicateFactory(new WebFluxProperties());
5974
HostRoutePredicateFactory hostRoutePredicateFactory = new HostRoutePredicateFactory();
6075
Predicate<ServerWebExchange> predicate = pathRoutePredicateFactory.apply(pathRoutePredicateFactory.newConfig())
6176
.and(hostRoutePredicateFactory.apply(hostRoutePredicateFactory.newConfig()));
@@ -68,4 +83,57 @@ public void predicateVisitVisitsEachNode() {
6883
HostRoutePredicateFactory.Config.class);
6984
}
7085

86+
@Test
87+
public void pathRoutePredicateVisitWithSetWebfluxBasePath() {
88+
WebFluxProperties webFluxProperties = new WebFluxProperties();
89+
webFluxProperties.setBasePath("/gw/api/v1");
90+
91+
PathRoutePredicateFactory pathRoutePredicateFactory = new PathRoutePredicateFactory(webFluxProperties);
92+
PathRoutePredicateFactory.Config config = new PathRoutePredicateFactory.Config()
93+
.setPatterns(List.of("/temp/**"))
94+
.setMatchTrailingSlash(true);
95+
96+
Predicate<ServerWebExchange> predicate = pathRoutePredicateFactory.apply(config);
97+
98+
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("http://127.0.0.1:8080/gw/api/v1/temp/test").build());
99+
100+
assertThat(predicate.test(exchange)).isEqualTo(true);
101+
}
102+
103+
@Test
104+
public void pathRoutePredicateVisitWithSetWebfluxBasePathStripPrefix() {
105+
WebFluxProperties webFluxProperties = new WebFluxProperties();
106+
webFluxProperties.setBasePath("/gw/api/v1");
107+
108+
PathRoutePredicateFactory pathRoutePredicateFactory = new PathRoutePredicateFactory(webFluxProperties);
109+
PathRoutePredicateFactory.Config config = new PathRoutePredicateFactory.Config()
110+
.setPatterns(List.of("/temp/**"))
111+
.setMatchTrailingSlash(true);
112+
113+
Predicate<ServerWebExchange> predicate = pathRoutePredicateFactory.apply(config);
114+
115+
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("http://127.0.0.1:8080/gw/api/v1/temp/test").build());
116+
117+
assertThat(predicate.test(exchange)).isEqualTo(true);
118+
119+
// webflux base path strips prefix is 3
120+
GatewayFilter filter = new StripPrefixGatewayFilterFactory().apply(c -> c.setParts(3));
121+
122+
GatewayFilterChain filterChain = mock(GatewayFilterChain.class);
123+
124+
ArgumentCaptor<ServerWebExchange> captor = ArgumentCaptor.forClass(ServerWebExchange.class);
125+
when(filterChain.filter(captor.capture())).thenReturn(Mono.empty());
126+
127+
filter.filter(exchange, filterChain);
128+
129+
ServerWebExchange webExchange = captor.getValue();
130+
131+
assertThat(webExchange.getRequest().getURI()).hasPath("/temp/test");
132+
133+
URI requestUrl = webExchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);
134+
assertThat(requestUrl).hasScheme("http").hasHost("127.0.0.1").hasPort(8080).hasPath("/temp/test");
135+
136+
LinkedHashSet<URI> uris = webExchange.getRequiredAttribute(GATEWAY_ORIGINAL_REQUEST_URL_ATTR);
137+
assertThat(uris).contains(exchange.getRequest().getURI());
138+
}
71139
}

spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicateFactoryTests.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.springframework.beans.factory.annotation.Value;
2525
import org.springframework.boot.SpringBootConfiguration;
2626
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
27+
import org.springframework.boot.autoconfigure.web.reactive.WebFluxProperties;
2728
import org.springframework.boot.test.context.SpringBootTest;
2829
import org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping;
2930
import org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory.Config;
@@ -105,14 +106,14 @@ public void matchOptionalTrailingSeparatorCopiedToMatchTrailingSlash() {
105106
@Test
106107
public void toStringFormat() {
107108
Config config = new Config().setPatterns(Arrays.asList("patternA", "patternB")).setMatchTrailingSlash(false);
108-
Predicate predicate = new PathRoutePredicateFactory().apply(config);
109+
Predicate predicate = new PathRoutePredicateFactory(new WebFluxProperties()).apply(config);
109110
assertThat(predicate.toString()).contains("patternA").contains("patternB").contains("false");
110111
}
111112

112113
@Test
113114
public void toStringFormatMatchTrailingSlashTrue() {
114115
Config config = new Config().setPatterns(Arrays.asList("patternA", "patternB")).setMatchTrailingSlash(true);
115-
Predicate<ServerWebExchange> predicate = new PathRoutePredicateFactory().apply(config);
116+
Predicate<ServerWebExchange> predicate = new PathRoutePredicateFactory(new WebFluxProperties()).apply(config);
116117
assertThat(predicate.toString()).contains("patternA").contains("patternB").contains("true");
117118
}
118119

spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicatePathContainerAttrBenchMarkTests.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.openjdk.jmh.annotations.Threads;
3232
import org.openjdk.jmh.annotations.Warmup;
3333

34+
import org.springframework.boot.autoconfigure.web.reactive.WebFluxProperties;
3435
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
3536
import org.springframework.mock.web.server.MockServerWebExchange;
3637
import org.springframework.web.server.ServerWebExchange;
@@ -52,7 +53,7 @@ public class PathRoutePredicatePathContainerAttrBenchMarkTests {
5253
for (int i = 0; i < ROUTES_NUM; i++) {
5354
PathRoutePredicateFactory.Config config = new PathRoutePredicateFactory.Config()
5455
.setPatterns(Collections.singletonList(PATH_PATTERN_PREFIX + i)).setMatchTrailingSlash(true);
55-
Predicate<ServerWebExchange> predicate = new PathRoutePredicateFactory().apply(config);
56+
Predicate<ServerWebExchange> predicate = new PathRoutePredicateFactory(new WebFluxProperties()).apply(config);
5657
predicates.add(predicate);
5758
}
5859
}

spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/support/tagsprovider/GatewayPathTagsProviderTests.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import io.micrometer.core.instrument.Tags;
2323
import org.junit.jupiter.api.Test;
2424

25+
import org.springframework.boot.autoconfigure.web.reactive.WebFluxProperties;
2526
import org.springframework.cloud.gateway.handler.predicate.HostRoutePredicateFactory;
2627
import org.springframework.cloud.gateway.handler.predicate.MethodRoutePredicateFactory;
2728
import org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory;
@@ -53,7 +54,7 @@ void addPathToRoutes() {
5354
PathRoutePredicateFactory.Config pathConfig = new PathRoutePredicateFactory.Config().setPatterns(pathList);
5455
HostRoutePredicateFactory.Config hostConfig = new HostRoutePredicateFactory.Config()
5556
.setPatterns(Collections.singletonList("**.myhost.com"));
56-
Route route = Route.async().id("git").uri(ROUTE_URI).predicate(new PathRoutePredicateFactory().apply(pathConfig)
57+
Route route = Route.async().id("git").uri(ROUTE_URI).predicate(new PathRoutePredicateFactory(new WebFluxProperties()).apply(pathConfig)
5758
.and(new HostRoutePredicateFactory().apply(hostConfig))).build();
5859

5960
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(ROUTE_URI).build());
@@ -74,8 +75,8 @@ void addsMultiplePathToRoutes() {
7475

7576
PathRoutePredicateFactory.Config pathConfig = new PathRoutePredicateFactory.Config().setPatterns(pathList);
7677
PathRoutePredicateFactory.Config pathConfig2 = new PathRoutePredicateFactory.Config().setPatterns(pathList2);
77-
Route route = Route.async().id("git").uri(ROUTE_URI).predicate(new PathRoutePredicateFactory().apply(pathConfig)
78-
.or(new PathRoutePredicateFactory().apply(pathConfig2))).build();
78+
Route route = Route.async().id("git").uri(ROUTE_URI).predicate(new PathRoutePredicateFactory(new WebFluxProperties()).apply(pathConfig)
79+
.or(new PathRoutePredicateFactory(new WebFluxProperties()).apply(pathConfig2))).build();
7980

8081
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(ROUTE_URI).build());
8182
exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, route);

0 commit comments

Comments
 (0)