Support setting Spring.webflux.base-path and supporting it in path predicate
Signed-off-by: 郭付一男 <guofuyinan@gmail.com>
This commit is contained in:
@@ -56,6 +56,7 @@ import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.boot.autoconfigure.web.embedded.NettyWebServerFactoryCustomizer;
|
||||
import org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.reactive.WebFluxProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.PropertyMapper;
|
||||
import org.springframework.boot.ssl.SslBundles;
|
||||
@@ -190,6 +191,7 @@ import org.springframework.web.reactive.socket.server.upgrade.ReactorNettyReques
|
||||
* @author Mete Alpaslan Katırcıoğlu
|
||||
* @author Alberto C. Ríos
|
||||
* @author Olga Maciaszek-Sharma
|
||||
* @author FuYiNan Guo
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)
|
||||
@@ -471,8 +473,8 @@ public class GatewayAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnEnabledPredicate
|
||||
public PathRoutePredicateFactory pathRoutePredicateFactory() {
|
||||
return new PathRoutePredicateFactory();
|
||||
public PathRoutePredicateFactory pathRoutePredicateFactory(WebFluxProperties webFluxProperties) {
|
||||
return new PathRoutePredicateFactory(webFluxProperties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -24,8 +24,10 @@ import java.util.function.Predicate;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.boot.autoconfigure.web.reactive.WebFluxProperties;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.http.server.PathContainer;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.util.pattern.PathPattern;
|
||||
import org.springframework.web.util.pattern.PathPattern.PathMatchInfo;
|
||||
@@ -41,6 +43,7 @@ import static org.springframework.http.server.PathContainer.parsePath;
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
* @author Dhawal Kapil
|
||||
* @author FuYiNan Guo
|
||||
*/
|
||||
public class PathRoutePredicateFactory extends AbstractRoutePredicateFactory<PathRoutePredicateFactory.Config> {
|
||||
|
||||
@@ -50,8 +53,20 @@ public class PathRoutePredicateFactory extends AbstractRoutePredicateFactory<Pat
|
||||
|
||||
private PathPatternParser pathPatternParser = new PathPatternParser();
|
||||
|
||||
private final WebFluxProperties webFluxProperties;
|
||||
|
||||
/**
|
||||
* @deprecated {@link #PathRoutePredicateFactory(WebFluxProperties)}
|
||||
*/
|
||||
@Deprecated
|
||||
public PathRoutePredicateFactory() {
|
||||
super(Config.class);
|
||||
this.webFluxProperties = new WebFluxProperties();
|
||||
}
|
||||
|
||||
public PathRoutePredicateFactory(WebFluxProperties webFluxProperties) {
|
||||
super(Config.class);
|
||||
this.webFluxProperties = webFluxProperties;
|
||||
}
|
||||
|
||||
private static void traceMatch(String prefix, Object desired, Object actual, boolean match) {
|
||||
@@ -82,7 +97,16 @@ public class PathRoutePredicateFactory extends AbstractRoutePredicateFactory<Pat
|
||||
synchronized (this.pathPatternParser) {
|
||||
pathPatternParser.setMatchOptionalTrailingSeparator(config.isMatchTrailingSlash());
|
||||
config.getPatterns().forEach(pattern -> {
|
||||
PathPattern pathPattern = this.pathPatternParser.parse(pattern);
|
||||
String basePath = webFluxProperties.getBasePath();
|
||||
boolean basePathIsNotBlank = StringUtils.hasText(basePath);
|
||||
String pathPatternStr = pattern;
|
||||
if (basePathIsNotBlank) {
|
||||
if (pattern.length() > 1 && !pattern.startsWith("/")) {
|
||||
basePath += ("/");
|
||||
}
|
||||
pathPatternStr = basePath + pattern;
|
||||
}
|
||||
PathPattern pathPattern = this.pathPatternParser.parse(pathPatternStr);
|
||||
pathPatterns.add(pathPattern);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -16,25 +16,41 @@
|
||||
|
||||
package org.springframework.cloud.gateway.handler.predicate;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.boot.autoconfigure.web.reactive.WebFluxProperties;
|
||||
import org.springframework.cloud.gateway.filter.GatewayFilter;
|
||||
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||
import org.springframework.cloud.gateway.filter.factory.StripPrefixGatewayFilterFactory;
|
||||
import org.springframework.cloud.gateway.handler.AsyncPredicate;
|
||||
import org.springframework.cloud.gateway.route.Route;
|
||||
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
|
||||
import org.springframework.mock.web.server.MockServerWebExchange;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR;
|
||||
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
* @author FuYiNan Guo
|
||||
*/
|
||||
public class GatewayPredicateVisitorTests {
|
||||
|
||||
@Test
|
||||
public void asyncPredicateVisitVisitsEachNode() {
|
||||
PathRoutePredicateFactory pathRoutePredicateFactory = new PathRoutePredicateFactory();
|
||||
PathRoutePredicateFactory pathRoutePredicateFactory = new PathRoutePredicateFactory(new WebFluxProperties());
|
||||
HostRoutePredicateFactory hostRoutePredicateFactory = new HostRoutePredicateFactory();
|
||||
ReadBodyRoutePredicateFactory readBodyRoutePredicateFactory1 = new ReadBodyRoutePredicateFactory();
|
||||
ReadBodyRoutePredicateFactory readBodyRoutePredicateFactory2 = new ReadBodyRoutePredicateFactory();
|
||||
@@ -55,7 +71,7 @@ public class GatewayPredicateVisitorTests {
|
||||
|
||||
@Test
|
||||
public void predicateVisitVisitsEachNode() {
|
||||
PathRoutePredicateFactory pathRoutePredicateFactory = new PathRoutePredicateFactory();
|
||||
PathRoutePredicateFactory pathRoutePredicateFactory = new PathRoutePredicateFactory(new WebFluxProperties());
|
||||
HostRoutePredicateFactory hostRoutePredicateFactory = new HostRoutePredicateFactory();
|
||||
Predicate<ServerWebExchange> predicate = pathRoutePredicateFactory.apply(pathRoutePredicateFactory.newConfig())
|
||||
.and(hostRoutePredicateFactory.apply(hostRoutePredicateFactory.newConfig()));
|
||||
@@ -68,4 +84,59 @@ public class GatewayPredicateVisitorTests {
|
||||
.hasExactlyElementsOfTypes(PathRoutePredicateFactory.Config.class, HostRoutePredicateFactory.Config.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pathRoutePredicateVisitWithSetWebfluxBasePath() {
|
||||
WebFluxProperties webFluxProperties = new WebFluxProperties();
|
||||
webFluxProperties.setBasePath("/gw/api/v1");
|
||||
|
||||
PathRoutePredicateFactory pathRoutePredicateFactory = new PathRoutePredicateFactory(webFluxProperties);
|
||||
PathRoutePredicateFactory.Config config = new PathRoutePredicateFactory.Config()
|
||||
.setPatterns(List.of("/temp/**"))
|
||||
.setMatchTrailingSlash(true);
|
||||
|
||||
Predicate<ServerWebExchange> predicate = pathRoutePredicateFactory.apply(config);
|
||||
|
||||
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("http://127.0.0.1:8080/gw/api/v1/temp/test")
|
||||
.build());
|
||||
|
||||
assertThat(predicate.test(exchange)).isEqualTo(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pathRoutePredicateVisitWithSetWebfluxBasePathStripPrefix() {
|
||||
WebFluxProperties webFluxProperties = new WebFluxProperties();
|
||||
webFluxProperties.setBasePath("/gw/api/v1");
|
||||
|
||||
PathRoutePredicateFactory pathRoutePredicateFactory = new PathRoutePredicateFactory(webFluxProperties);
|
||||
PathRoutePredicateFactory.Config config = new PathRoutePredicateFactory.Config()
|
||||
.setPatterns(List.of("/temp/**"))
|
||||
.setMatchTrailingSlash(true);
|
||||
|
||||
Predicate<ServerWebExchange> predicate = pathRoutePredicateFactory.apply(config);
|
||||
|
||||
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("http://127.0.0.1:8080/gw/api/v1/temp/test")
|
||||
.build());
|
||||
|
||||
assertThat(predicate.test(exchange)).isEqualTo(true);
|
||||
|
||||
// webflux base path strips prefix is 3
|
||||
GatewayFilter filter = new StripPrefixGatewayFilterFactory().apply(c -> c.setParts(3));
|
||||
|
||||
GatewayFilterChain filterChain = mock(GatewayFilterChain.class);
|
||||
|
||||
ArgumentCaptor<ServerWebExchange> captor = ArgumentCaptor.forClass(ServerWebExchange.class);
|
||||
when(filterChain.filter(captor.capture())).thenReturn(Mono.empty());
|
||||
|
||||
filter.filter(exchange, filterChain);
|
||||
|
||||
ServerWebExchange webExchange = captor.getValue();
|
||||
|
||||
assertThat(webExchange.getRequest().getURI()).hasPath("/temp/test");
|
||||
|
||||
URI requestUrl = webExchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);
|
||||
assertThat(requestUrl).hasScheme("http").hasHost("127.0.0.1").hasPort(8080).hasPath("/temp/test");
|
||||
|
||||
LinkedHashSet<URI> uris = webExchange.getRequiredAttribute(GATEWAY_ORIGINAL_REQUEST_URL_ATTR);
|
||||
assertThat(uris).contains(exchange.getRequest().getURI());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.reactive.WebFluxProperties;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping;
|
||||
import org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory.Config;
|
||||
@@ -133,14 +134,14 @@ public class PathRoutePredicateFactoryTests extends BaseWebClientTests {
|
||||
@Test
|
||||
public void toStringFormat() {
|
||||
Config config = new Config().setPatterns(Arrays.asList("patternA", "patternB")).setMatchTrailingSlash(false);
|
||||
Predicate predicate = new PathRoutePredicateFactory().apply(config);
|
||||
Predicate predicate = new PathRoutePredicateFactory(new WebFluxProperties()).apply(config);
|
||||
assertThat(predicate.toString()).contains("patternA").contains("patternB").contains("false");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toStringFormatMatchTrailingSlashTrue() {
|
||||
Config config = new Config().setPatterns(Arrays.asList("patternA", "patternB")).setMatchTrailingSlash(true);
|
||||
Predicate<ServerWebExchange> predicate = new PathRoutePredicateFactory().apply(config);
|
||||
Predicate<ServerWebExchange> predicate = new PathRoutePredicateFactory(new WebFluxProperties()).apply(config);
|
||||
assertThat(predicate.toString()).contains("patternA").contains("patternB").contains("true");
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.openjdk.jmh.annotations.Mode;
|
||||
import org.openjdk.jmh.annotations.Threads;
|
||||
import org.openjdk.jmh.annotations.Warmup;
|
||||
|
||||
import org.springframework.boot.autoconfigure.web.reactive.WebFluxProperties;
|
||||
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
|
||||
import org.springframework.mock.web.server.MockServerWebExchange;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
@@ -54,7 +55,7 @@ public class PathRoutePredicatePathContainerAttrBenchMarkTests {
|
||||
PathRoutePredicateFactory.Config config = new PathRoutePredicateFactory.Config()
|
||||
.setPatterns(Collections.singletonList(PATH_PATTERN_PREFIX + i))
|
||||
.setMatchTrailingSlash(true);
|
||||
Predicate<ServerWebExchange> predicate = new PathRoutePredicateFactory().apply(config);
|
||||
Predicate<ServerWebExchange> predicate = new PathRoutePredicateFactory(new WebFluxProperties()).apply(config);
|
||||
predicates.add(predicate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.List;
|
||||
import io.micrometer.core.instrument.Tags;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.web.reactive.WebFluxProperties;
|
||||
import org.springframework.cloud.gateway.handler.predicate.HostRoutePredicateFactory;
|
||||
import org.springframework.cloud.gateway.handler.predicate.MethodRoutePredicateFactory;
|
||||
import org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory;
|
||||
@@ -56,7 +57,7 @@ public class GatewayPathTagsProviderTests {
|
||||
Route route = Route.async()
|
||||
.id("git")
|
||||
.uri(ROUTE_URI)
|
||||
.predicate(new PathRoutePredicateFactory().apply(pathConfig)
|
||||
.predicate(new PathRoutePredicateFactory(new WebFluxProperties()).apply(pathConfig)
|
||||
.and(new HostRoutePredicateFactory().apply(hostConfig)))
|
||||
.build();
|
||||
|
||||
@@ -81,8 +82,8 @@ public class GatewayPathTagsProviderTests {
|
||||
Route route = Route.async()
|
||||
.id("git")
|
||||
.uri(ROUTE_URI)
|
||||
.predicate(new PathRoutePredicateFactory().apply(pathConfig)
|
||||
.or(new PathRoutePredicateFactory().apply(pathConfig2)))
|
||||
.predicate(new PathRoutePredicateFactory(new WebFluxProperties()).apply(pathConfig)
|
||||
.or(new PathRoutePredicateFactory(new WebFluxProperties()).apply(pathConfig2)))
|
||||
.build();
|
||||
|
||||
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(ROUTE_URI).build());
|
||||
|
||||
Reference in New Issue
Block a user