diff --git a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/RedirectToGatewayFilterFactory.java b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/RedirectToGatewayFilterFactory.java index 3d9254e4..3433c896 100644 --- a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/RedirectToGatewayFilterFactory.java +++ b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/RedirectToGatewayFilterFactory.java @@ -59,16 +59,11 @@ public class RedirectToGatewayFilterFactory extends AbstractGatewayFilterFactory public GatewayFilter apply(String statusString, String urlString) { final HttpStatus httpStatus = parse(statusString); Assert.isTrue(httpStatus.is3xxRedirection(), "status must be a 3xx code, but was " + statusString); - final URL url; - try { - url = URI.create(urlString).toURL(); - } catch (MalformedURLException e) { - throw new IllegalArgumentException("Invalid url " + urlString, e); - } + final URI url = URI.create(urlString); return apply(httpStatus, url); } - public GatewayFilter apply(HttpStatus httpStatus, URL url) { + public GatewayFilter apply(HttpStatus httpStatus, URI uri) { return (exchange, chain) -> chain.filter(exchange).then(Mono.defer(() -> { @@ -76,7 +71,7 @@ public class RedirectToGatewayFilterFactory extends AbstractGatewayFilterFactory setResponseStatus(exchange, httpStatus); final ServerHttpResponse response = exchange.getResponse(); - response.getHeaders().set(HttpHeaders.LOCATION, url.toString()); + response.getHeaders().set(HttpHeaders.LOCATION, uri.toString()); return response.setComplete(); } return Mono.empty(); diff --git a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java index e3a9d8f6..32c40dcf 100644 --- a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java +++ b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java @@ -17,6 +17,7 @@ package org.springframework.cloud.gateway.route.builder; import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import java.util.Collection; import java.util.Optional; @@ -266,7 +267,7 @@ public class GatewayFilterSpec extends UriSpec { * @return a {@link GatewayFilterSpec} that can be used to apply additional filters */ public GatewayFilterSpec redirect(String status, URI url) { - return redirect(status, url.toString()); + return redirect(status, url); } /** @@ -286,7 +287,11 @@ public class GatewayFilterSpec extends UriSpec { * @return a {@link GatewayFilterSpec} that can be used to apply additional filters */ public GatewayFilterSpec redirect(HttpStatus status, URL url) { - return filter(getBean(RedirectToGatewayFilterFactory.class).apply(status, url)); + try { + return filter(getBean(RedirectToGatewayFilterFactory.class).apply(status, url.toURI())); + } catch (URISyntaxException e) { + throw new IllegalArgumentException("Invalid URL", e); + } } /** diff --git a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory/RedirectToGatewayFilterFactoryTests.java b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory/RedirectToGatewayFilterFactoryTests.java index fb7e4295..a766a326 100644 --- a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory/RedirectToGatewayFilterFactoryTests.java +++ b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory/RedirectToGatewayFilterFactoryTests.java @@ -22,7 +22,10 @@ import org.junit.runner.RunWith; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.gateway.route.RouteLocator; +import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; import org.springframework.cloud.gateway.test.BaseWebClientTests; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; @@ -46,9 +49,29 @@ public class RedirectToGatewayFilterFactoryTests extends BaseWebClientTests { .expectHeader().valueEquals(HttpHeaders.LOCATION, "http://example.org"); } + @Test + public void redirectToRelativeUrlFilterWorks() { + testClient.get() + .uri("/") + .header("Host", "www.relativeredirect.org") + .exchange() + .expectStatus().isEqualTo(HttpStatus.FOUND) + .expectHeader().valueEquals(HttpHeaders.LOCATION, "/index.html#/customers"); + } + @EnableAutoConfiguration @SpringBootConfiguration @Import(DefaultTestConfig.class) - public static class TestConfig { } + public static class TestConfig { + + @Bean + public RouteLocator testRouteLocator(RouteLocatorBuilder builder) { + return builder.routes() + .route("relative_redirect", r -> r.host("**.relativeredirect.org") + .filters(f -> f.redirect(302, "/index.html#/customers")) + .uri("no://op")) + .build(); + } + } }