diff --git a/spring-cloud/spring-cloud-gateway/pom.xml b/spring-cloud/spring-cloud-gateway/pom.xml
index dcad2b7da6..a352bbd4e4 100644
--- a/spring-cloud/spring-cloud-gateway/pom.xml
+++ b/spring-cloud/spring-cloud-gateway/pom.xml
@@ -177,5 +177,21 @@
+
+
+ gateway-url-rewrite
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+ com.baeldung.springcloudgateway.rewrite.URLRewriteGatewayApplication
+ -Dspring.profiles.active=url-rewrite
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/rewrite/URLRewriteGatewayApplication.java b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/rewrite/URLRewriteGatewayApplication.java
new file mode 100644
index 0000000000..46541b4826
--- /dev/null
+++ b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/rewrite/URLRewriteGatewayApplication.java
@@ -0,0 +1,25 @@
+/**
+ *
+ */
+package com.baeldung.springcloudgateway.rewrite;
+
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.cloud.gateway.filter.GatewayFilter;
+
+import reactor.core.publisher.Mono;
+
+/**
+ * @author Baeldung
+ *
+ */
+@SpringBootApplication
+public class URLRewriteGatewayApplication {
+
+ public static void main(String[] args) {
+ new SpringApplicationBuilder(URLRewriteGatewayApplication.class)
+ .profiles("url-rewrite")
+ .run(args);
+ }
+
+}
diff --git a/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/rewrite/routes/DynamicRewriteRoute.java b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/rewrite/routes/DynamicRewriteRoute.java
new file mode 100644
index 0000000000..29d40d7021
--- /dev/null
+++ b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/rewrite/routes/DynamicRewriteRoute.java
@@ -0,0 +1,43 @@
+package com.baeldung.springcloudgateway.rewrite.routes;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cloud.gateway.route.RouteLocator;
+import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+
+import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR;
+import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.addOriginalRequestUrl;
+
+import java.util.Random;
+
+@Configuration
+@Profile("url-rewrite")
+public class DynamicRewriteRoute {
+
+ @Value("${rewrite.backend.uri}")
+ private String backendUri;
+ private static Random rnd = new Random();
+
+ @Bean
+ public RouteLocator dynamicZipCodeRoute(RouteLocatorBuilder builder) {
+ return builder.routes()
+ .route("dynamicRewrite", r ->
+ r.path("/v2/zip/**")
+ .filters(f -> f.filter((exchange, chain) -> {
+ ServerHttpRequest req = exchange.getRequest();
+ addOriginalRequestUrl(exchange, req.getURI());
+ String path = req.getURI().getRawPath();
+ String newPath = path.replaceAll(
+ "/v2/zip/(?.*)",
+ "/api/zip/${zipcode}-" + String.format("%03d", rnd.nextInt(1000)));
+ ServerHttpRequest request = req.mutate().path(newPath).build();
+ exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, request.getURI());
+ return chain.filter(exchange.mutate().request(request).build());
+ }))
+ .uri(backendUri))
+ .build();
+ }
+}
diff --git a/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/webfilters/WebFilterGatewayApplication.java b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/webfilters/WebFilterGatewayApplication.java
index 852e5cadba..9e212cc4bf 100644
--- a/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/webfilters/WebFilterGatewayApplication.java
+++ b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/webfilters/WebFilterGatewayApplication.java
@@ -8,7 +8,7 @@ public class WebFilterGatewayApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(WebFilterGatewayApplication.class)
- .profiles("webfilters")
+ .profiles("url-rewrite")
.run(args);
}
diff --git a/spring-cloud/spring-cloud-gateway/src/main/resources/application-nosecurity.yml b/spring-cloud/spring-cloud-gateway/src/main/resources/application-nosecurity.yml
new file mode 100644
index 0000000000..40a52ded0f
--- /dev/null
+++ b/spring-cloud/spring-cloud-gateway/src/main/resources/application-nosecurity.yml
@@ -0,0 +1,8 @@
+# Enable this profile to disable security
+spring:
+ autoconfigure:
+ exclude:
+ - org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
+ - org.springframework.boot.actuate.autoconfigure.ManagementSecurityAutoConfiguration
+ - org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration
+ - org.springframework.boot.actuate.autoconfigure.security.reactive.ReactiveManagementWebSecurityAutoConfiguration
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-gateway/src/main/resources/application-url-rewrite.yml b/spring-cloud/spring-cloud-gateway/src/main/resources/application-url-rewrite.yml
new file mode 100644
index 0000000000..b2656151db
--- /dev/null
+++ b/spring-cloud/spring-cloud-gateway/src/main/resources/application-url-rewrite.yml
@@ -0,0 +1,11 @@
+spring:
+ cloud:
+ gateway:
+ routes:
+ - id: rewrite_v1
+ uri: ${rewrite.backend.uri:http://example.com}
+ predicates:
+ - Path=/v1/customer/**
+ filters:
+ - RewritePath=/v1/customer/(?.*),/api/$\{segment}
+
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/springcloudgateway/rewrite/URLRewriteGatewayApplicationLiveTest.java b/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/springcloudgateway/rewrite/URLRewriteGatewayApplicationLiveTest.java
new file mode 100644
index 0000000000..41fe37045c
--- /dev/null
+++ b/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/springcloudgateway/rewrite/URLRewriteGatewayApplicationLiveTest.java
@@ -0,0 +1,109 @@
+package com.baeldung.springcloudgateway.rewrite;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+
+import org.junit.AfterClass;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
+import org.springframework.boot.web.server.LocalServerPort;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.DynamicPropertyRegistry;
+import org.springframework.test.context.DynamicPropertySource;
+import org.springframework.test.web.reactive.server.WebTestClient;
+
+import com.sun.net.httpserver.HttpServer;
+
+@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
+@ActiveProfiles({ "nosecurity", "url-rewrite" })
+class URLRewriteGatewayApplicationLiveTest {
+
+ // NOTE for Eclipse users: By default, Eclipse will complain about com.sun.** classes.
+ // To solve this issue, follow instructions available at the :
+ // https://stackoverflow.com/questions/13155734/eclipse-cant-recognize-com-sun-net-httpserver-httpserver-package
+ private static HttpServer mockServer;
+ private static Logger log = LoggerFactory.getLogger(URLRewriteGatewayApplicationLiveTest.class);
+
+ // Create a running HttpServer that echoes back the request URL.
+ private static HttpServer startTestServer() {
+
+ try {
+ log.info("[I26] Starting mock server");
+ mockServer = HttpServer.create();
+ mockServer.bind(new InetSocketAddress(0), 0);
+ mockServer.createContext("/api", (xchg) -> {
+ String uri = xchg.getRequestURI()
+ .toString();
+ log.info("[I23] Backend called: uri={}", uri);
+ xchg.getResponseHeaders()
+ .add("Content-Type", "text/plain");
+ xchg.sendResponseHeaders(200, 0);
+ OutputStream os = xchg.getResponseBody();
+ os.write(uri.getBytes());
+ os.flush();
+ os.close();
+ });
+
+ mockServer.start();
+ InetSocketAddress localAddr = mockServer.getAddress();
+ log.info("[I36] mock server started: local address={}", localAddr);
+
+ return mockServer;
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+
+ }
+
+ // TIP: https://www.baeldung.com/spring-dynamicpropertysource
+ @DynamicPropertySource
+ static void registerBackendServer(DynamicPropertyRegistry registry) {
+ registry.add("rewrite.backend.uri", () -> {
+ HttpServer s = startTestServer();
+ return "http://localhost:" + s.getAddress().getPort();
+ });
+ }
+
+ @AfterClass
+ public static void stopMockBackend() throws Exception {
+ log.info("[I40] Shutdown mock http server");
+ mockServer.stop(5);
+ }
+
+ @LocalServerPort
+ private int localPort;
+
+ @Test
+ void testWhenApiCall_thenRewriteSuccess(@Autowired WebTestClient webClient) {
+ webClient.get()
+ .uri("http://localhost:" + localPort + "/v1/customer/customer1")
+ .exchange()
+ .expectBody()
+ .consumeWith((result) -> {
+ String body = new String(result.getResponseBody());
+ log.info("[I99] body={}", body);
+ assertEquals("/api/customer1", body);
+ });
+ }
+
+ @Test
+ void testWhenDslCall_thenRewriteSuccess(@Autowired WebTestClient webClient) {
+ webClient.get()
+ .uri("http://localhost:" + localPort + "/v2/zip/123456")
+ .exchange()
+ .expectBody()
+ .consumeWith((result) -> {
+ String body = new String(result.getResponseBody());
+ log.info("[I99] body={}", body);
+ assertTrue(body.matches("/api/zip/123456-\\d{3}"));
+ });
+ }
+
+}