From b382bb6cf09a4e9617d93dbfc50b5366c8b3869f Mon Sep 17 00:00:00 2001 From: spring-builds Date: Sat, 22 Mar 2025 13:26:55 +0000 Subject: [PATCH 1/2] Bumping versions --- .../server/mvc/filter/BeforeFilterFunctions.java | 6 +++++- .../mvc/filter/BeforeFilterFunctionsTests.java | 15 ++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java index c96fffdd..dba4e260 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java @@ -332,7 +332,11 @@ public abstract class BeforeFilterFunctions { String path = request.uri().getPath(); String newPath = pattern.matcher(path).replaceAll(normalizedReplacement); - URI rewrittenUri = UriComponentsBuilder.fromUri(request.uri()).replacePath(newPath).encode().build().toUri(); + URI rewrittenUri = UriComponentsBuilder.fromUri(request.uri()) + .replacePath(newPath) + .encode() + .build() + .toUri(); ServerRequest modified = ServerRequest.from(request).uri(rewrittenUri).build(); diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java index 309b81bf..ae6a7ee2 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java @@ -184,8 +184,7 @@ class BeforeFilterFunctionsTests { @Test void rewritePath() { - MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/get") - .buildRequest(null); + MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/get").buildRequest(null); ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList()); @@ -197,7 +196,7 @@ class BeforeFilterFunctionsTests { @Test void rewritePathWithSpace() { MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/get/path/with spaces") - .buildRequest(null); + .buildRequest(null); ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList()); @@ -209,7 +208,7 @@ class BeforeFilterFunctionsTests { @Test void rewritePathWithEnDash() { MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/get/path/with–en–dashes") - .buildRequest(null); + .buildRequest(null); ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList()); @@ -220,14 +219,16 @@ class BeforeFilterFunctionsTests { @Test void rewritePathWithEnDashAndSpace() { - MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/get/path/with–en–dashes and spaces") - .buildRequest(null); + MockHttpServletRequest servletRequest = MockMvcRequestBuilders + .get("http://localhost/get/path/with–en–dashes and spaces") + .buildRequest(null); ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList()); ServerRequest modified = BeforeFilterFunctions.rewritePath("get", "modified").apply(request); - assertThat(modified.uri().getRawPath()).isEqualTo("/modified/path/with%E2%80%93en%E2%80%93dashes%20and%20spaces"); + assertThat(modified.uri().getRawPath()) + .isEqualTo("/modified/path/with%E2%80%93en%E2%80%93dashes%20and%20spaces"); } } From 55b3cd0c51b907430f830c1b7a1ed2b1a827d4a6 Mon Sep 17 00:00:00 2001 From: Spencer Gibb Date: Fri, 28 Mar 2025 14:59:19 -0400 Subject: [PATCH 2/2] Fixes routing issue with path filters and static uri (#3747) * Fixes routing issue with path filters and static uri The problem arises from when MvcUtils.setRequestUrl is called depending on if the route was created via config, using `http(uri)` or having it set in a before filter. To fix this, the uri is now always set in a before filter and the `http(uri)` methods are deprecated in favor of a BeforeFilterFunctions.uri() method. A new DefaultHandlerSupplier was created to use an updated HandlerDiscoverer.Result that has fields for lowerPrecedenceFilters and higherPrecedenceFilters as the `http()` family of Handler methods need associated filters. This results in a more consistent handling of the request url attribute. Existing methods and constructors are deprecated. Fixes gh-3736 --- .../filters/addrequestheader.adoc | 20 ++- .../addrequestheadersifnotpresent.adoc | 28 +++- .../filters/addrequestparameter.adoc | 26 ++-- .../filters/addresponseheader.adoc | 20 ++- .../filters/circuitbreaker-filter.adoc | 32 ++-- .../filters/deduperesponseheader.adoc | 7 +- .../filters/fallback-headers.adoc | 8 +- .../filters/maprequestheader.adoc | 8 +- .../filters/modifyrequestbody.adoc | 14 +- .../filters/modifyresponsebody.adoc | 25 +--- .../filters/prefixpath.adoc | 12 +- .../filters/preservehostheader.adoc | 12 +- .../filters/ratelimiter.adoc | 14 +- .../filters/redirectto.adoc | 12 +- .../filters/removerequestheader.adoc | 14 +- .../filters/removerequestparameter.adoc | 16 +- .../filters/removeresponseheader.adoc | 10 +- .../filters/requestheadersize.adoc | 12 +- .../filters/requestsize.adoc | 10 +- .../filters/retry.adoc | 23 +-- .../rewritelocationresponseheader.adoc | 13 +- .../filters/rewritepath.adoc | 10 +- .../filters/rewriterequestparameter.adoc | 12 +- .../filters/rewriteresponseheader.adoc | 12 +- .../filters/setpath.adoc | 10 +- .../filters/setrequestheader.adoc | 24 +-- .../filters/setrequesthostheader.adoc | 10 +- .../filters/setresponseheader.adoc | 20 ++- .../filters/setstatus.adoc | 13 +- .../filters/stripprefix.adoc | 16 +- .../filters/tokenrelay.adoc | 12 +- .../gateway-request-predicates.adoc | 121 ++++++++------- .../java-routes-api.adoc | 14 +- ...writing-custom-predicates-and-filters.adoc | 35 +++-- .../config/RouterFunctionHolderFactory.java | 21 +-- .../mvc/filter/BeforeFilterFunctions.java | 15 +- .../server/mvc/filter/FilterFunctions.java | 9 ++ .../filter/LoadBalancerHandlerSupplier.java | 2 +- .../XForwardedRequestHeadersFilter.java | 2 +- .../mvc/handler/DefaultHandlerSupplier.java | 92 ++++++++++++ .../server/mvc/handler/HandlerDiscoverer.java | 25 +++- .../server/mvc/handler/HandlerFunctions.java | 23 ++- .../main/resources/META-INF/spring.factories | 2 +- .../server/mvc/ServerMvcIntegrationTests.java | 30 +++- .../filter/BeforeFilterFunctionsTests.java | 12 ++ .../filter/StripPrefixStaticPortTests.java | 141 ++++++++++++++++++ .../mvc/test/HttpbinTestcontainers.java | 5 - .../application-stripprefixstaticport.yml | 12 ++ 48 files changed, 754 insertions(+), 282 deletions(-) create mode 100644 spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/DefaultHandlerSupplier.java create mode 100644 spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/StripPrefixStaticPortTests.java create mode 100644 spring-cloud-gateway-server-mvc/src/test/resources/application-stripprefixstaticport.yml diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/addrequestheader.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/addrequestheader.adoc index d189f531..0b0921a1 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/addrequestheader.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/addrequestheader.adoc @@ -14,6 +14,8 @@ spring: routes: - id: add_request_header_route uri: https://example.org + predicates: + - Path=/red filters: - AddRequestHeader=X-Request-red, blue ---- @@ -21,6 +23,7 @@ spring: .GatewaySampleApplication.java [source,java] ---- +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.addRequestHeader; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -30,8 +33,10 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsAddReqHeader() { - return route(GET("/red"), http("https://example.org")) - .before(addRequestHeader("X-Request-red", "blue")); + return route("add_request_header_route") + .GET("/red", http()) + .before(uri("https://example.org")) + .before(addRequestHeader("X-Request-red", "blue")); } } ---- @@ -45,13 +50,20 @@ The following example configures an `AddRequestHeader` filter that uses a variab .GatewaySampleApplication.java [source,java] ---- +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.addRequestHeader; +import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; +import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; + @Configuration class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsAddReqHeader() { - return route(GET("/red/{segment}"), http("https://example.org")) - .before(addRequestHeader("X-Request-red", "blue-{segment}")); + return route("add_request_header_route") + .GET("/red/{segment}", http()) + .before(uri("https://example.org")) + .before(addRequestHeader("X-Request-red", "blue-{segment}")); } } ---- diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/addrequestheadersifnotpresent.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/addrequestheadersifnotpresent.adoc index b4455a6b..fda40278 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/addrequestheadersifnotpresent.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/addrequestheadersifnotpresent.adoc @@ -12,8 +12,10 @@ spring: gateway: mvc: routes: - - id: add_request_headers_route + - id: add_request_headers_route_inp uri: https://example.org + predicates: + - Path=/red filters: - AddRequestHeadersIfNotPresent=X-Request-Color-1:blue,X-Request-Color-2:green ---- @@ -21,6 +23,7 @@ spring: .GatewaySampleApplication.java [source,java] ---- +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.addRequestHeadersIfNotPresent; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -29,9 +32,11 @@ import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFuncti class RouteConfiguration { @Bean - public RouterFunction gatewayRouterFunctionsAddReqHeader() { - return route(GET("/red"), http("https://example.org")) - .before(addRequestHeadersIfNotPresent("X-Request-Color-1:blue","X-Request-Color-2:green")); + public RouterFunction gatewayRouterFunctionsAddReqHeaderInp() { + return route("add_request_headers_route_inp") + .GET("/red", http()) + .before(uri("https://example.org")) + .before(addRequestHeadersIfNotPresent("X-Request-Color-1:blue","X-Request-Color-2:green")); } } ---- @@ -49,13 +54,20 @@ The following example configures an `AddRequestHeadersIfNotPresent` filter that .GatewaySampleApplication.java [source,java] ---- +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.addRequestHeadersIfNotPresent; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; +import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; +import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; + @Configuration class RouteConfiguration { @Bean - public RouterFunction gatewayRouterFunctionsAddReqHeader() { - return route(GET("/red/{segment}"), http("https://example.org")) - .before(addRequestHeadersIfNotPresent("X-Request-red", "blue-{segment}")); + public RouterFunction gatewayRouterFunctionsAddReqHeaderInp() { + return route("add_request_header_route_inp") + .GET("/red/{segment}", http()) + .before(uri("https://example.org")) + .before(addRequestHeadersIfNotPresent("X-Request-red", "blue-{segment}")); } } ---- @@ -66,7 +78,7 @@ spring: cloud: gateway: routes: - - id: add_request_header_route + - id: add_request_header_route_inp uri: https://example.org predicates: - Path=/red/{segment} diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/addrequestparameter.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/addrequestparameter.adoc index 6ce332b4..53d306ad 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/addrequestparameter.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/addrequestparameter.adoc @@ -14,6 +14,8 @@ spring: routes: - id: add_request_parameter_route uri: https://example.org + predicates: + - Path=/anything/addrequestparam filters: - AddRequestParameter=red, blue ---- @@ -21,6 +23,7 @@ spring: .GatewaySampleApplication.java [source,java] ---- +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.addRequestParameter; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -29,11 +32,12 @@ import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFuncti class RouteConfiguration { @Bean - public RouterFunction gatewayRouterFunctionsAddReqHeader() { - return route("add_request_parameter_route") - .GET("/anything/addrequestparam", http("https://example.org")) - .before(addRequestParameter("red", "blue")) - .build(); + public RouterFunction gatewayRouterFunctionsAddReqParameter() { + return route("add_request_parameter_route") + .GET("/anything/addrequestparam", http()) + .before(uri("https://example.org")) + .before(addRequestParameter("red", "blue")) + .build(); } } ---- @@ -47,6 +51,7 @@ The following example configures an `AddRequestParameter` filter that uses a var .GatewaySampleApplication.java [source,java] ---- +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.addRequestParameter; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -56,11 +61,12 @@ import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequ class RouteConfiguration { @Bean - public RouterFunction gatewayRouterFunctionsAddReqHeader() { - return route("add_request_parameter_route") - .route(host("{segment}.myhost.org"), http("https://example.org")) - .before(addRequestParameter("foo", "bar-{segment}")) - .build(); + public RouterFunction gatewayRouterFunctionsAddReqParameter() { + return route("add_request_parameter_route") + .route(host("{segment}.myhost.org"), http()) + .before(uri("https://example.org")) + .before(addRequestParameter("foo", "bar-{segment}")) + .build(); } } ---- \ No newline at end of file diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/addresponseheader.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/addresponseheader.adoc index e04ed408..0c678abd 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/addresponseheader.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/addresponseheader.adoc @@ -14,6 +14,8 @@ spring: routes: - id: add_response_header_route uri: https://example.org + predicates: + - Path=/anything/addresheader filters: - AddResponseHeader=X-Response-Red, Blue ---- @@ -21,6 +23,7 @@ spring: .GatewaySampleApplication.java [source,java] ---- +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.filter.AfterFilterFunctions.addResponseHeader; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -30,9 +33,10 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsAddRespHeader() { - return route("addresponseheader") - .GET("/anything/addresheader", http("https://example.org")) - .after(addResponseHeader("X-Response-Red", "Blue")) + return route("add_response_header_route") + .GET("/anything/addresheader", http()) + .before(uri("https://example.org")) + .after(addResponseHeader("X-Response-Red", "Blue")) .build(); } } @@ -47,6 +51,7 @@ The following example configures an `AddResponseHeader` filter that uses a varia .GatewaySampleApplication.java [source,java] ---- +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.filter.AfterFilterFunctions.addResponseHeader; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -57,10 +62,11 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsAddRespHeader() { - return route("add_response_header_route") - .route(host("{segment}.myhost.org"), http("https://example.org")) - .after(addResponseHeader("foo", "bar-{segment}")) - .build(); + return route("add_response_header_route") + .route(host("{segment}.myhost.org"), http()) + .before(uri("https://example.org")) + .after(addResponseHeader("foo", "bar-{segment}")) + .build(); } } ---- diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/circuitbreaker-filter.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/circuitbreaker-filter.adoc index 8ec00ffd..8a1a50c8 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/circuitbreaker-filter.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/circuitbreaker-filter.adoc @@ -15,14 +15,17 @@ spring: gateway: mvc: routes: - - id: circuitbreaker_route + - id: circuitbreakernofallback uri: https://example.org + predicates: + - Path=/anything/circuitbreakernofallback filters: - CircuitBreaker=myCircuitBreaker ---- .GatewaySampleApplication.java [source,java] ---- +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.filter.CircuitBreakerFilterFunctions.circuitBreaker; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -33,9 +36,10 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsCircuitBreakerNoFallback() { return route("circuitbreakernofallback") - .route(path("/anything/circuitbreakernofallback"), http("https://example.org")) - .filter(circuitBreaker("mycb3")) - .build(); + .route(path("/anything/circuitbreakernofallback"), http()) + .before(uri("https://example.org")) + .filter(circuitBreaker("myCircuitBreaker")) + .build(); } } ---- @@ -74,6 +78,7 @@ The following listing does the same thing in Java: [source,java] ---- import java.net.URI; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.filter.CircuitBreakerFilterFunctions.circuitBreaker; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -84,9 +89,10 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsCircuitBreakerFallback() { return route("circuitbreaker_route") - .route(path("/consumingServiceEndpoint"), http("https://example.org")) - .filter(circuitBreaker("myCircuitBreaker", URI.create("forward:/inCaseOfFailureUseThis"))) - .build(); + .route(path("/consumingServiceEndpoint"), http()) + .before(uri("https://example.org")) + .filter(circuitBreaker("myCircuitBreaker", URI.create("forward:/inCaseOfFailureUseThis"))) + .build(); } } ---- @@ -102,6 +108,7 @@ In the example below the call `consumingServiceEndpoint/users/1` will be redirec [source,java] ---- import java.net.URI; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.filter.CircuitBreakerFilterFunctions.circuitBreaker; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -112,9 +119,10 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsCircuitBreakerFallback() { return route("circuitbreaker_route") - .route(path("/consumingServiceEndpoint/{*segments}"), http("https://example.org")) - .filter(circuitBreaker("myCircuitBreaker", URI.create("forward:/inCaseOfFailureUseThis/{segments}"))) - .build(); + .route(path("/consumingServiceEndpoint/{*segments}"), http()) + .before(uri("https://example.org")) + .filter(circuitBreaker("myCircuitBreaker", URI.create("forward:/inCaseOfFailureUseThis/{segments}"))) + .build(); } } ---- @@ -126,6 +134,7 @@ However, you can also reroute the request to a controller or handler in an exter .GatewaySampleApplication.java [source,java] ---- +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.filter.CircuitBreakerFilterFunctions.circuitBreaker; import static org.springframework.cloud.gateway.server.mvc.filter.LoadBalancerFilterFunctions.lb; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; @@ -142,7 +151,8 @@ class RouteConfiguration { .filter(circuitBreaker("fetchIngredients", URI.create("forward:/fallback"))) .build() .and(route("ingredients-fallback") - .route(path("/fallback"), http("http://localhost:9994")) + .route(path("/fallback"), http()) + .before(uri("https://localhost:9994")) .build()); } } diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/deduperesponseheader.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/deduperesponseheader.adoc index 9659f2cf..5f8a7a23 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/deduperesponseheader.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/deduperesponseheader.adoc @@ -14,6 +14,8 @@ spring: routes: - id: dedupe_response_header_route uri: https://example.org + predicates: + - Path=/hello filters: - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin ---- @@ -21,18 +23,19 @@ spring: [source,java] ---- import static org.springframework.cloud.gateway.server.mvc.filter.AfterFilterFunctions.dedupeResponseHeader; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; import static org.springframework.web.servlet.function.RequestPredicates.path; - @Configuration class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsDedupeResponseHeader() { return route("dedupe_response_header_route") - .route(path("/hello"), http("https://example.org")) + .route(path("/hello"), http()) + .before(uri("https://example.org")) .after(dedupeResponseHeader("Access-Control-Allow-Credentials Access-Control-Allow-Origin")) .build(); } diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/fallback-headers.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/fallback-headers.adoc index 22f4114b..300276ac 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/fallback-headers.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/fallback-headers.adoc @@ -14,7 +14,7 @@ spring: - id: ingredients uri: lb://ingredients predicates: - - Path=//ingredients/** + - Path=/ingredients/** filters: - name: CircuitBreaker args: @@ -33,8 +33,9 @@ spring: .GatewaySampleApplication.java [source,java] ---- -import static org.springframework.cloud.gateway.server.mvc.filter.CircuitBreakerFilterFunctions.circuitBreaker; import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.fallbackHeaders; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; +import static org.springframework.cloud.gateway.server.mvc.filter.CircuitBreakerFilterFunctions.circuitBreaker; import static org.springframework.cloud.gateway.server.mvc.filter.LoadBalancerFilterFunctions.lb; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -50,7 +51,8 @@ class RouteConfiguration { .filter(circuitBreaker("fetchIngredients", URI.create("forward:/fallback"))) .build() .and(route("ingredients-fallback") - .route(path("/fallback"), http("http://localhost:9994")) + .route(path("/fallback"), http()) + .before(uri("http://localhost:9994")) .before(fallbackHeaders()) .build()); } diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/maprequestheader.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/maprequestheader.adoc index 2f8f30b6..e85d08b9 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/maprequestheader.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/maprequestheader.adoc @@ -17,6 +17,8 @@ spring: routes: - id: map_request_header_route uri: https://example.org + predicates: + - Path=/mypath filters: - MapRequestHeader=Blue, X-Request-Red ---- @@ -24,7 +26,8 @@ spring: .GatewaySampleApplication.java [source,java] ---- -import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.addRequestParameter; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.mapRequestHeader; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -34,7 +37,8 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsMapRequestHeader() { return route("map_request_header_route") - .GET("/mypath", http("https://example.org")) + .GET("/mypath", http()) + .before(uri("https://example.org")) .before(mapRequestHeader("Blue", "X-Request-Red")) .build(); } diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/modifyrequestbody.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/modifyrequestbody.adoc index 963b26f0..a18dbff1 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/modifyrequestbody.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/modifyrequestbody.adoc @@ -11,6 +11,7 @@ The following listing shows how to modify a request body filter: [source,java] ---- import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.modifyRequestBody; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.host; @@ -20,12 +21,13 @@ import org.springframework.http.MediaType; class RouteConfiguration { @Bean - public RouterFunction gatewayRouterFunctionsAddReqHeader() { - return route("rewrite_request_obj") - .route(host("*.rewriterequestobj.org"), http("https://example.org")) - .before(modifyRequestBody(String.class, Hello.class, MediaType.APPLICATION_JSON_VALUE, - (request, s) -> new Hello(s.toUpperCase()))) - .build(); + public RouterFunction gatewayRouterFunctionsModifyRequestBody() { + return route("modify_request_body") + .route(host("*.modifyrequestbody.org"), http()) + .before(uri("https://example.org")) + .before(modifyRequestBody(String.class, Hello.class, MediaType.APPLICATION_JSON_VALUE, + (request, s) -> new Hello(s.toUpperCase()))) + .build(); } record Hello(String message) { } diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/modifyresponsebody.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/modifyresponsebody.adoc index f8211ed0..c8a8d9d7 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/modifyresponsebody.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/modifyresponsebody.adoc @@ -7,22 +7,11 @@ NOTE: This filter can be configured only by using the Java DSL. The following listing shows how to modify a response body filter: -[source,java] ----- -@Bean -public RouteLocator routes(RouteLocatorBuilder builder) { - return builder.routes() - .route("rewrite_response_upper", r -> r.host("*.rewriteresponseupper.org") - .filters(f -> f.prefixPath("/httpbin") - .modifyResponseBody(String.class, String.class, - (exchange, s) -> Mono.just(s.toUpperCase()))).uri(uri)) - .build(); -} ----- .GatewaySampleApplication.java [source,java] ---- import static org.springframework.cloud.gateway.server.mvc.filter.AfterFilterFunctions.modifyResponseBody; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.host; @@ -32,11 +21,13 @@ import org.springframework.http.MediaType; class RouteConfiguration { @Bean - public RouterFunction gatewayRouterFunctionsAddReqHeader() { - return route("rewrite_request_obj") - .route(host("*.rewriterequestobj.org"), http("https://example.org")) - .before(modifyResponseBody(String.class, String.class, MediaType.APPLICATION_JSON_VALUE, (request, s) -> s.toUpperCase())) - .build(); + public RouterFunction gatewayRouterFunctionsModifyResponseBody() { + return route("modify_response_bodu") + .route(host("*.modifyresponsebodu.org"), http()) + .before(uri("https://example.org")) + .after(modifyResponseBody(String.class, String.class, MediaType.APPLICATION_JSON_VALUE, + (request, s) -> s.toUpperCase())) + .build(); } } diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/prefixpath.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/prefixpath.adoc index 5bc8b5e8..5a4d1343 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/prefixpath.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/prefixpath.adoc @@ -15,6 +15,8 @@ spring: routes: - id: prefixpath_route uri: https://example.org + predicates: + - Path=/** filters: - PrefixPath=/mypath ---- @@ -22,6 +24,7 @@ spring: .GatewaySampleApplication.java [source,java] ---- +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.prefixPath; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -31,10 +34,11 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsPrefixPath() { - return route("prefixpath_route") - .GET("/**", http("https://example.org")) - .before(prefixPath("/mypath")) - .build(); + return route("prefixpath_route") + .GET("/**", http()) + .before(uri("https://example.org")) + .before(prefixPath("/mypath")) + .build(); } } ---- diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/preservehostheader.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/preservehostheader.adoc index 518c0ac3..462cf01f 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/preservehostheader.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/preservehostheader.adoc @@ -16,6 +16,8 @@ spring: routes: - id: preserve_host_route uri: https://example.org + predicates: + - Path=/** filters: - PreserveHostHeader ---- @@ -23,6 +25,7 @@ spring: .GatewaySampleApplication.java [source,java] ---- +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.preserveHostHeader; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -32,10 +35,11 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsPreserveHostHeader() { - return route("preserve_host_route") - .GET("/**", http("https://example.org")) - .before(preserveHostHeader()) - .build(); + return route("preserve_host_route") + .GET("/**", http()) + .before(uri("https://example.org")) + .before(preserveHostHeader()) + .build(); } } ---- diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/ratelimiter.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/ratelimiter.adoc index cfde996c..7fa31982 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/ratelimiter.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/ratelimiter.adoc @@ -47,6 +47,7 @@ The following is an example of configuring a route with rate limiting: .RouteConfiguration.java [source,java] ---- +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.filter.Bucket4jFilterFunctions.rateLimit; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -56,12 +57,13 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsRateLimited() { - return route("rate_limited_route") - .GET("/api/**", http("https://example.org")) - .filter(rateLimit(c -> c.setCapacity(100) - .setPeriod(Duration.ofMinutes(1)) - .setKeyResolver(request -> request.servletRequest().getUserPrincipal().getName()))) - .build(); + return route("rate_limited_route") + .GET("/api/**", http()) + .before(uri("https://example.org")) + .filter(rateLimit(c -> c.setCapacity(100) + .setPeriod(Duration.ofMinutes(1)) + .setKeyResolver(request -> request.servletRequest().getUserPrincipal().getName()))) + .build(); } } ---- diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/redirectto.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/redirectto.adoc index f1816d36..69f2d538 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/redirectto.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/redirectto.adoc @@ -18,6 +18,8 @@ spring: routes: - id: redirectto_route uri: https://example.org + predicates: + - Path=/** filters: - RedirectTo=302, https://acme.org ---- @@ -25,6 +27,7 @@ spring: .GatewaySampleApplication.java [source,java] ---- +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.filter.FilterFunctions.redirectTo; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -34,10 +37,11 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsRedirectTo() { - return route("redirectto_route") - .GET("/**", http("https://example.org")) - .filter(redirectTo(302, URI.create("acme.org"))) - .build(); + return route("redirectto_route") + .GET("/**", http()) + .before(uri("https://example.org")) + .filter(redirectTo(302, URI.create("acme.org"))) + .build(); } } ---- diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/removerequestheader.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/removerequestheader.adoc index c85e8d9a..03150906 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/removerequestheader.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/removerequestheader.adoc @@ -16,6 +16,8 @@ spring: routes: - id: removerequestheader_route uri: https://example.org + predicates: + - Path=/** filters: - RemoveRequestHeader=X-Request-Foo ---- @@ -23,6 +25,7 @@ spring: .GatewaySampleApplication.java [source,java] ---- +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.removeRequestHeader; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -31,11 +34,12 @@ import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFuncti class RouteConfiguration { @Bean - public RouterFunction gatewayRouterFunctionsremoveRequestHeader() { - return route("removerequestheader_route") - .GET("/**", http("https://example.org")) - .before(removeRequestHeader("X-Request-Foo")) - .build(); + public RouterFunction gatewayRouterFunctionsRemoveRequestHeader() { + return route("removerequestheader_route") + .GET("/**", http()) + .before(uri("https://example.org")) + .before(removeRequestHeader("X-Request-Foo")) + .build(); } } ---- diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/removerequestparameter.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/removerequestparameter.adoc index 5ff79940..e60eaa9d 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/removerequestparameter.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/removerequestparameter.adoc @@ -16,6 +16,8 @@ spring: routes: - id: removerequestparameter_route uri: https://example.org + predicates: + - Path=/** filters: - RemoveRequestParameter=red ---- @@ -23,7 +25,8 @@ spring: .GatewaySampleApplication.java [source,java] ---- -import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.addRequestParameter; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.removeRequestParameter; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -31,11 +34,12 @@ import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFuncti class RouteConfiguration { @Bean - public RouterFunction gatewayRouterFunctionsAddReqHeader() { - return route("removerequestparameter_route") - .GET("/**", http("https://example.org")) - .before(removeRequestParameter("red")) - .build(); + public RouterFunction gatewayRouterFunctionsRemoveRequestParameter() { + return route("removerequestparameter_route") + .GET("/**", http()) + .before(uri("https://example.org")) + .before(removeRequestParameter("red")) + .build(); } } ---- diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/removeresponseheader.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/removeresponseheader.adoc index fda397b1..d767aba0 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/removeresponseheader.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/removeresponseheader.adoc @@ -15,6 +15,8 @@ spring: routes: - id: removeresponseheader_route uri: https://example.org + predicates: + - Path=/anything/removeresponseheader filters: - RemoveResponseHeader=X-Response-Foo ---- @@ -22,6 +24,7 @@ spring: .GatewaySampleApplication.java [source,java] ---- +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.filter.AfterFilterFunctions.removeResponseHeader; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -31,9 +34,10 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsRemoveResponseHeader() { - return route("addresponseheader") - .GET("/anything/addresheader", http("https://example.org")) - .after(removeResponseHeader("X-Response-Foo")) + return route("removeresponseheader_route") + .GET("/anything/removeresponseheader", http()) + .before(uri("https://example.org")) + .after(removeResponseHeader("X-Response-Foo")) .build(); } } diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/requestheadersize.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/requestheadersize.adoc index 5f8f4066..e94b2ff0 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/requestheadersize.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/requestheadersize.adoc @@ -16,6 +16,8 @@ spring: routes: - id: requestheadersize_route uri: https://example.org + predicates: + - Path=/** filters: - RequestHeaderSize=1000B ---- @@ -23,6 +25,7 @@ spring: .GatewaySampleApplication.java [source,java] ---- +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.requestHeaderSize; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -32,10 +35,11 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsRequestHeaderSize() { - return route("requestheadersize_route") - .GET("/**", http("https://example.org")) - .before(requestHeaderSize("1000B")) - .build(); + return route("requestheadersize_route") + .GET("/**", http()) + .before(uri("https://example.org")) + .before(requestHeaderSize("1000B")) + .build(); } } ---- diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/requestsize.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/requestsize.adoc index 29135ea8..7eb84314 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/requestsize.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/requestsize.adoc @@ -28,6 +28,7 @@ spring: .GatewaySampleApplication.java [source,java] ---- +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.requestSize; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -37,10 +38,11 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsRequestSize() { - return route("request_size_route") - .GET("/upload", http("http://localhost:8080")) - .before(requestSize("5000000")) - .build(); + return route("request_size_route") + .GET("/upload", http()) + .before(uri("http://localhost:8080")) + .before(requestSize("5000000")) + .build(); } } ---- diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/retry.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/retry.adoc index 96165f0d..be99e402 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/retry.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/retry.adoc @@ -36,7 +36,7 @@ spring: gateway: mvc: routes: - - id: retry_test + - id: retry_route uri: http://localhost:8080/flakey predicates: - Host=*.retry.com @@ -53,6 +53,7 @@ spring: .GatewaySampleApplication.java [source,java] ---- +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.filter.FilterFunctions.adaptCachedBody; import static org.springframework.cloud.gateway.server.mvc.filter.RetryFilterFunctions.retry; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; @@ -63,12 +64,16 @@ import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequ class RouteConfiguration { @Bean - public RouterFunction gatewayRouterFunctionsAddReqHeader() { - return route("add_request_parameter_route") - .route(host("*.retry.com"), http("https://example.org")) - .filter(retry(config -> config.setRetries(3).setSeries(Set.of(HttpStatus.Series.SERVER_ERROR)).setMethods(Set.of(HttpMethod.GET, HttpMethod.POST)).setCacheBody(true))) - .filter(adaptCachedBody()) - .build(); + public RouterFunction gatewayRouterFunctionsRetry() { + return route("retry_route") + .route(host("*.retry.com"), http()) + .before(uri("http://localhost:8080/flakey")) + .filter(retry(config -> config.setRetries(3) + .setSeries(Set.of(HttpStatus.Series.SERVER_ERROR)) + .setMethods(Set.of(HttpMethod.GET, HttpMethod.POST)) + .setCacheBody(true))) + .filter(adaptCachedBody()) + .build(); } } ---- @@ -77,11 +82,11 @@ NOTE: When using the retry filter with a `forward:` prefixed URL, the target end For example, if the target endpoint is an annotated controller, the target controller method should not return `ResponseEntity` with an error status code. Instead, it should throw an `Exception` or signal an error (for example, through a `Mono.error(ex)` return value), which the retry filter can be configured to handle by retrying. -// WARNING: When using the retry filter with any HTTP method with a body, the body will be cached and the gateway will become memory constrained. The body is cached in a request attribute defined by `ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR`. The type of the object is `org.springframework.core.io.buffer.DataBuffer`. +WARNING: When using the retry filter with any HTTP method with a body and `cacheBody=true`, the body will be cached and the gateway will become memory constrained. The body is cached in a request attribute defined by `MvcUtils.CACHED_REQUEST_BODY_ATT`. The type of the object is `ByteArrayInputStream`. A simplified "shortcut" notation can be added with a single `status` and `method`. -The following two examples are equivalent: +The following two example routes are equivalent: .application.yml [source,yaml] diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/rewritelocationresponseheader.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/rewritelocationresponseheader.adoc index 28918320..6af573a1 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/rewritelocationresponseheader.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/rewritelocationresponseheader.adoc @@ -15,6 +15,8 @@ spring: routes: - id: rewritelocationresponseheader_route uri: http://example.org + predicates: + - Path=/** filters: - RewriteLocationResponseHeader=AS_IN_REQUEST, Location, , ---- @@ -22,7 +24,8 @@ spring: .GatewaySampleApplication.java [source,java] ---- -import static org.springframework.cloud.gateway.server.mvc.filter.AfterFilterFunctions.addResponseHeader; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; +import static org.springframework.cloud.gateway.server.mvc.filter.RewriteLocationResponseHeaderFilterFunctions.rewriteLocationResponseHeader; import static org.springframework.cloud.gateway.server.mvc.filter.RewriteLocationResponseHeaderFilterFunctions.StripVersion; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -33,9 +36,11 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsRewriteLocationResponseHeader() { return route("rewritelocationresponseheader_route") - .GET("/**", http("https://example.org")) - .after(rewriteLocationResponseHeader(config -> config.setLocationHeaderName("Location").setStripVersion(StripVersion.AS_IN_REQUEST))) - .build(); + .GET("/**", http()) + .before(uri("https://example.org")) + .after(rewriteLocationResponseHeader(config -> config.setLocationHeaderName("Location") + .setStripVersion(StripVersion.AS_IN_REQUEST))) + .build(); } } ---- diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/rewritepath.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/rewritepath.adoc index 3b50b615..d423af39 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/rewritepath.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/rewritepath.adoc @@ -25,6 +25,7 @@ spring: [source,java] ---- import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.rewritePath; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -33,10 +34,11 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsRewritePath() { - return route("rewritepath_route") - .GET("/red/**", http("https://example.org")) - .before(rewritePath("/red/(?.*)", "/${segment}")) - .build(); + return route("rewritepath_route") + .GET("/red/**", http()) + .before(uri("https://example.org")) + .before(rewritePath("/red/(?.*)", "/${segment}")) + .build(); } } ---- diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/rewriterequestparameter.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/rewriterequestparameter.adoc index ba7c38c5..7ad61594 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/rewriterequestparameter.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/rewriterequestparameter.adoc @@ -26,6 +26,7 @@ spring: [source,java] ---- import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.addRequestParameter; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -33,11 +34,12 @@ import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFuncti class RouteConfiguration { @Bean - public RouterFunction gatewayRouterFunctionsAddReqHeader() { - return route("add_request_parameter_route") - .GET("/anything/addrequestparam", http("https://example.org")) - .before(addRequestParameter("red", "blue")) - .build(); + public RouterFunction gatewayRouterFunctionsRewriteRequestParameter() { + return route("rewriterequestparameter_route") + .GET("products", http()) + .before(uri("https://example.org")) + .before(addRequestParameter("red", "blue")) + .build(); } } ---- diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/rewriteresponseheader.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/rewriteresponseheader.adoc index 7ba0f9b0..7e0cb2c9 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/rewriteresponseheader.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/rewriteresponseheader.adoc @@ -16,14 +16,17 @@ spring: routes: - id: rewriteresponseheader_route uri: https://example.org + predicates: + - Path=/** filters: - - RewriteResponseHeader=X-Response-Red, , password=[^&]+, password=*** + - RewriteResponseHeader=X-Response-Red, password=[^&]+, password=*** ---- .GatewaySampleApplication.java [source,java] ---- -import static org.springframework.cloud.gateway.server.mvc.filter.AfterFilterFunctions.addResponseHeader; +import static org.springframework.cloud.gateway.server.mvc.filter.AfterFilterFunctions.rewriteResponseHeader; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -33,8 +36,9 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsRewriteResponseHeader() { return route("rewriteresponseheader_route") - .GET("/**", http("https://example.org")) - .after(rewriteResponseHeader("X-Request-Red", "password=[^&]+", "password=***")) + .GET("/**", http()) + .before(uri("https://example.org")) + .after(rewriteResponseHeader("X-Request-Red", "password=[^&]+", "password=***")) .build(); } } diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/setpath.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/setpath.adoc index 9355a068..73624a70 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/setpath.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/setpath.adoc @@ -27,6 +27,7 @@ spring: [source,java] ---- import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.setPath; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -35,10 +36,11 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsSetPath() { - return route("add_request_parameter_route") - .GET("/red/{segment}", http("https://example.org")) - .before(setPath("/{segment")) - .build(); + return route("setpath_route") + .GET("/red/{segment}", http()) + .before(uri("https://example.org")) + .before(setPath("/{segment")) + .build(); } } ---- diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/setrequestheader.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/setrequestheader.adoc index f131486a..a2c7676b 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/setrequestheader.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/setrequestheader.adoc @@ -14,6 +14,8 @@ spring: routes: - id: setrequestheader_route uri: https://example.org + predicates: + - Path=/** filters: - SetRequestHeader=X-Request-Red, Blue ---- @@ -22,6 +24,7 @@ spring: [source,java] ---- import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.setRequestHostHeader; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -30,10 +33,11 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsSetRequestHeader() { - return route("add_request_parameter_route") - .GET("/**", http("https://example.org")) - .before(setRequestHostHeader("X-Request-Red", "Blue")) - .build(); + return route("setrequestheader_route") + .GET("/**", http()) + .before(uri("https://example.org")) + .before(setRequestHostHeader("X-Request-Red", "Blue")) + .build(); } } ---- @@ -64,19 +68,21 @@ spring: [source,java] ---- import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.setRequestHostHeader; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; -import static import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.host; +import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.host; @Configuration class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsSetRequestHeader() { - return route("add_request_parameter_route") - .route(host("{segment}.myhost.org"), http("https://example.org")) - .before(setRequestHostHeader("X-Request-Red", "Blue-{segment}")) - .build(); + return route("setrequestheader_route") + .route(host("{segment}.myhost.org"), http()) + .before(uri("https://example.org")) + .before(setRequestHostHeader("X-Request-Red", "Blue-{segment}")) + .build(); } } ---- \ No newline at end of file diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/setrequesthostheader.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/setrequesthostheader.adoc index 3f8faad9..d12b23c6 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/setrequesthostheader.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/setrequesthostheader.adoc @@ -26,6 +26,7 @@ spring: .GatewaySampleApplication.java [source,java] ---- +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.setRequestHostHeader; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -35,10 +36,11 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsSetRequestHostHeader() { - return route("set_request_host_header_route") - .GET("/headers", http("http://localhost:8080")) - .before(setRequestHostHeader("example.org")) - .build(); + return route("set_request_host_header_route") + .GET("/headers", http()) + .before(uri("http://localhost:8080")) + .before(setRequestHostHeader("example.org")) + .build(); } } ---- diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/setresponseheader.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/setresponseheader.adoc index ee7698e9..55375546 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/setresponseheader.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/setresponseheader.adoc @@ -14,6 +14,8 @@ spring: routes: - id: setresponseheader_route uri: https://example.org + predicates: + - Path=/anything/setresponseheader filters: - SetResponseHeader=X-Response-Red, Blue ---- @@ -22,6 +24,7 @@ spring: [source,java] ---- import static org.springframework.cloud.gateway.server.mvc.filter.AfterFilterFunctions.setResponseHeader; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -30,9 +33,10 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsSetResponseHeader() { - return route("addresponseheader") - .GET("/anything/addresheader", http("https://example.org")) - .after(setResponseHeader("X-Response-Red", "Blue")) + return route("setresponseheader_route") + .GET("/anything/setresponseheader", http()) + .before(uri("https://example.org")) + .after(setResponseHeader("X-Response-Red", "Blue")) .build(); } } @@ -64,6 +68,7 @@ spring: [source,java] ---- import static org.springframework.cloud.gateway.server.mvc.filter.AfterFilterFunctions.setResponseHeader; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.host; @@ -73,10 +78,11 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsSetResponseHeader() { - return route("add_response_header_route") - .route(host("{segment}.myhost.org"), http("https://example.org")) - .after(setResponseHeader("foo", "bar-{segment}")) - .build(); + return route("setresponseheader_route") + .route(host("{segment}.myhost.org"), http()) + .before(uri("https://example.org")) + .after(setResponseHeader("foo", "bar-{segment}")) + .build(); } } ---- diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/setstatus.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/setstatus.adoc index c3022b52..bd9bbe25 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/setstatus.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/setstatus.adoc @@ -16,10 +16,14 @@ spring: routes: - id: setstatusstring_route uri: https://example.org + predicates: + - Path=/path1 filters: - SetStatus=UNAUTHORIZED - id: setstatusint_route uri: https://example.org + predicates: + - Path=/path2 filters: - SetStatus=401 ---- @@ -28,6 +32,7 @@ spring: [source,java] ---- import static org.springframework.cloud.gateway.server.mvc.filter.AfterFilterFunctions.setStatus; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -37,13 +42,15 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsSetStatus() { return route("setstatus_route") - .GET("/path1", http("https://example.org")) + .GET("/path1", http()) + .before(uri("https://example.org")) // setStatus("UNAUTHORIZED") works as well .after(setStatus(HttpStatus.UNAUTHORIZED)) .build().and(route("setstatusint_route") - .GET("/path2", http("https://example.org")) + .before(uri("https://example.org")) + .GET("/path2", http()) .after(setStatus("401")) - .build()); + .build()); } } ---- diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/stripprefix.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/stripprefix.adoc index dc2be798..902974ce 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/stripprefix.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/stripprefix.adoc @@ -13,8 +13,8 @@ spring: gateway: mvc: routes: - - id: nameRoot - uri: https://nameservice + - id: strip_prefix_route + uri: https://example.org predicates: - Path=/name/** filters: @@ -25,6 +25,7 @@ spring: [source,java] ---- import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.stripPrefix; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -33,14 +34,15 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsStripPrefix() { - return route("nameRoot") - .GET("/name/**", http("https://example.org")) - .before(stripPrefix(2)) - .build(); + return route("strip_prefix_route") + .GET("/name/**", http()) + .before(uri("https://example.org")) + .before(stripPrefix(2)) + .build(); } } ---- -When a request is made through the gateway to `/name/blue/red`, the request made to `nameservice` looks like `https://nameservice/red`. +When a request is made through the gateway to `/name/blue/red`, the full request url looks like `https://example.org/red`. WARNING: If using the `lb()` filter, it needs to be after the `stripPrefix()` filter, otherwise the resulting url could be incorrect. The `lb:` scheme handler in configuration, automatically puts the filter in the highest precedence order. \ No newline at end of file diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/tokenrelay.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/tokenrelay.adoc index 2bf618aa..086bd3eb 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/tokenrelay.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/tokenrelay.adoc @@ -54,6 +54,7 @@ Spring Cloud Gateway Server MVC can forward the OAuth2 access token of the curre .RouteConfiguration.java [source,java] ---- +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.filter.TokenRelayFilterFunctions.tokenRelay; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -62,11 +63,12 @@ import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFuncti class RouteConfiguration { @Bean - public RouterFunction gatewayRouterFunctionsAddReqHeader() { - return route("resource") - .GET("/resource", http("http://localhost:9000")) - .filter(tokenRelay()) - .build(); + public RouterFunction gatewayRouterFunctionsTokenRelay() { + return route("resource") + .GET("/resource", http()) + .before(uri("https://localhost:9000")) + .filter(tokenRelay()) + .build(); } } ---- diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/gateway-request-predicates.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/gateway-request-predicates.adoc index 1bca61e6..5631cbf8 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/gateway-request-predicates.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/gateway-request-predicates.adoc @@ -31,6 +31,7 @@ spring: [source,java] ---- import java.time.ZonedDateTime; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.after; @@ -40,9 +41,10 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsAfter() { - return route("after_route") - .route(after(ZonedDateTime.parse("2017-01-20T17:42:47.789-07:00[America/Denver]")), http("https://example.org")) - .build(); + return route("after_route") + .route(after(ZonedDateTime.parse("2017-01-20T17:42:47.789-07:00[America/Denver]")), http()) + .before(uri("https://example.org")) + .build(); } } ---- @@ -74,6 +76,7 @@ spring: [source,java] ---- import java.time.ZonedDateTime; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.before; @@ -83,9 +86,10 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsBefore() { - return route("before_route") - .route(before(ZonedDateTime.parse("2017-01-20T17:42:47.789-07:00[America/Denver]")), http("https://example.org")) - .build(); + return route("before_route") + .route(before(ZonedDateTime.parse("2017-01-20T17:42:47.789-07:00[America/Denver]")), http() + .before(uri("https://example.org")) + .build(); } } ---- @@ -119,6 +123,7 @@ spring: [source,java] ---- import java.time.ZonedDateTime; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.between; @@ -128,9 +133,11 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsBetween() { - return route("between_route") - .route(between(ZonedDateTime.parse("2017-01-20T17:42:47.789-07:00[America/Denver]"), ZonedDateTime.parse("2017-01-21T17:42:47.789-07:00[America/Denver]")), http("https://example.org")) - .build(); + return route("between_route") + .route(between(ZonedDateTime.parse("2017-01-20T17:42:47.789-07:00[America/Denver]"), + ZonedDateTime.parse("2017-01-21T17:42:47.789-07:00[America/Denver]")), http()) + .before(uri("https://example.org")) + .build(); } } ---- @@ -162,18 +169,20 @@ spring: .GatewaySampleApplication.java [source,java] ---- +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; -import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.between; +import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.cookie; @Configuration class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsCookie() { - return route("cookie_route") - .route(cookie("chocolate", "ch.p"), http("https://example.org")) - .build(); + return route("cookie_route") + .route(cookie("chocolate", "ch.p"), http()) + .before(uri("https://example.org")) + .build(); } } ---- @@ -204,6 +213,7 @@ spring: .GatewaySampleApplication.java [source,java] ---- +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.header; @@ -212,10 +222,11 @@ import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequ class RouteConfiguration { @Bean - public RouterFunction gatewayRouterFunctionsCookie() { - return route("cookie_route") - .route(header("X-Request-Id", "\\d+"), http("https://example.org")) - .build(); + public RouterFunction gatewayRouterFunctionsHeader() { + return route("header_route") + .route(header("X-Request-Id", "\\d+"), http()) + .before(uri("https://example.org")) + .build(); } } ---- @@ -247,6 +258,7 @@ spring: .GatewaySampleApplication.java [source,java] ---- +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.host; @@ -256,9 +268,10 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsHost() { - return route("host_route") - .route(host("**.somehost.org", "**.anotherhost.org"), http("https://example.org")) - .build(); + return route("host_route") + .route(host("**.somehost.org", "**.anotherhost.org"), http()) + .before(uri("https://example.org")) + .build(); } } ---- @@ -296,6 +309,7 @@ spring: [source,java] ---- import org.springframework.http.HttpMethod; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.method; @@ -305,9 +319,10 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsMethod() { - return route("method_route") - .route(method(HttpMethod.GET, HttpMethod.POST), http("https://example.org")) - .build(); + return route("method_route") + .route(method(HttpMethod.GET, HttpMethod.POST), http()) + .before(uri("https://example.org")) + .build(); } } ---- @@ -319,19 +334,19 @@ This route matches if the request method was a `GET` or a `POST`. .GatewaySampleApplication.java [source,java] ---- -import org.springframework.http.HttpMethod; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; -import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.methods; @Configuration class RouteConfiguration { @Bean - public RouterFunction gatewayRouterFunctionsMethod() { - return route("method_route") - .GET("/mypath", http("https://example.org")) - .build(); + public RouterFunction gatewayRouterFunctionsMethodAndPath() { + return route("method_and_path_route") + .GET("/mypath", http()) + .before(uri("https://example.org")) + .build(); } } ---- @@ -363,19 +378,20 @@ spring: .GatewaySampleApplication.java [source,java] ---- -import org.springframework.http.HttpMethod; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; -import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.method; +import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.path; @Configuration class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsPath() { - return route("path_route") - .route(path("/red/{segment}", "/blue/{segment}"), http("https://example.org")) - .build(); + return route("path_route") + .route(path("/red/{segment}", "/blue/{segment}"), http()) + .before(uri("https://example.org")) + .build(); } } ---- @@ -421,7 +437,7 @@ spring: .GatewaySampleApplication.java [source,java] ---- -import org.springframework.http.HttpMethod; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.query; @@ -431,9 +447,10 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsQuery() { - return route("query_route") - .route(query("green"), http("https://example.org")) - .build(); + return route("query_route") + .route(query("green"), http()) + .before(uri("https://example.org")) + .build(); } } ---- @@ -457,7 +474,7 @@ spring: .GatewaySampleApplication.java [source,java] ---- -import org.springframework.http.HttpMethod; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.query; @@ -467,9 +484,10 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsQuery() { - return route("query_route") - .route(query("red", "gree."), http("https://example.org")) - .build(); + return route("query_route") + .route(query("red", "gree."), http()) + .before(uri("https://example.org")) + .build(); } } ---- @@ -585,22 +603,25 @@ spring: .GatewaySampleApplication.java [source,java] ---- -import org.springframework.http.HttpMethod; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; -import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.method; +import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.path; +import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.weight; @Configuration class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsWeights() { - return route("weight_high") - .route(weight("group1", 8).and(path("/**")), http("https://weighthigh.org")) - .build().and( - route("weight_low") - .route(weight("group1", 2).and(path("/**")), http("https://weightlow.org")) - .build()); + return route("weight_high") + .route(weight("group1", 8).and(path("/**")), http()) + .before(uri("https://weighthigh.org")) + .build().and( + route("weight_low") + .route(weight("group1", 2).and(path("/**")), http()) + .before(uri("https://weightlow.org")) + .build()); } } ---- diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/java-routes-api.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/java-routes-api.adoc index d15b79e0..f653d36e 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/java-routes-api.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/java-routes-api.adoc @@ -9,12 +9,15 @@ A https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springfra [source,java] ---- import static org.springframework.web.servlet.function.RouterFunctions.route; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; class SimpleGateway { @Bean public RouterFunction getRoute() { - return route().GET("/get", http("https://httpbin.org")).build(); + return route().GET("/get", http()) + .before(uri("https://example.org")) + .build(); } } ---- @@ -29,13 +32,16 @@ Some advanced filters require some metadata to be added to request attributes. T .GatewaySampleApplication.java [source,java] ---- +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; class SimpleGateway { @Bean public RouterFunction getRoute() { - return route("simple_route").GET("/get", http("https://httpbin.org")).build(); + return route("simple_route").GET("/get", http()) + .before(uri("https://example.org")) + .build(); } } ---- @@ -43,4 +49,6 @@ class SimpleGateway { [[gateway-handlerfunctions]] == Gateway MVC Handler Functions -Various `RouterFunctions.Builder` methods require a `HandlerFunction`. To create a route that is proxied by the MVC Gateway, `HandlerFunction` implementations are supplied in `org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions`. The most basic is the `http()` `HandlerFunction`. If a `URI` is supplied as a parameter, that is the `URI` used as the downstream target for sending the HTTP requests (as seen in the example above). If no parameter is passed, the function looks for a `URI` in the `org.springframework.cloud.gateway.server.mvc.common.MvcUtils.GATEWAY_REQUEST_URL_ATTR` request attribute. This allows for dynamic targets such as load balancing to set the `URI`. +Various `RouterFunctions.Builder` methods require a `HandlerFunction`. To create a route that is proxied by the MVC Gateway, `HandlerFunction` implementations are supplied in `org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions`. The most basic is the `http()` `HandlerFunction`. The function looks for a `URI` in the `org.springframework.cloud.gateway.server.mvc.common.MvcUtils.GATEWAY_REQUEST_URL_ATTR` request attribute. This allows for dynamic targets such as load balancing to set the `URI`. + +WARNING: As of version 4.1.7, `HandlerFunctions.http(String)` and `HandlerFunctions.http(URI)` are now deprecated. Please use `HandlerFunctions.http()` in combination with the `BeforeFilterFunctions.uri()` filter instead. This fixes inconsistencies in dealing with the route url request attribute. \ No newline at end of file diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/writing-custom-predicates-and-filters.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/writing-custom-predicates-and-filters.adoc index fdabf35d..30aef31e 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/writing-custom-predicates-and-filters.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/writing-custom-predicates-and-filters.adoc @@ -48,6 +48,7 @@ To use our new `headerExists` `RequestPredicate`, we need to plug it in to an ap [source,java] ---- import static SampleRequestPredicates.headerExists; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -56,9 +57,10 @@ class RouteConfiguration { @Bean public RouterFunction headerExistsRoute() { - return route("header_exists_route") - .route(headerExists("X-Green"), http("https://example.org")) - .build(); + return route("header_exists_route") + .route(headerExists("X-Green"), http()) + .before(uri("https://example.org")) + .build(); } } ---- @@ -111,6 +113,7 @@ First, a new `ServerRequest` is created from the existing request. This allows u [source,java] ---- import static SampleHandlerFilterFunctions.instrument; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -120,9 +123,10 @@ class RouteConfiguration { @Bean public RouterFunction instrumentRoute() { return route("instrument_route") - .GET("/**", http("https://example.org")) - .filter(instrument("X-Request-Id", "X-Response-Id")) - .build(); + .GET("/**", http()) + .filter(instrument("X-Request-Id", "X-Response-Id")) + .before(uri("https://example.org")) + .build(); } } ---- @@ -160,6 +164,7 @@ A new `ServerRequest` is created from the existing request. This allows us to ad [source,java] ---- import static SampleBeforeFilterFunctions.instrument; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -168,10 +173,10 @@ class RouteConfiguration { @Bean public RouterFunction instrumentRoute() { - return route("instrument_route") - .GET("/**", http("https://example.org")) - .before(instrument("X-Request-Id")) - .build(); + return route("instrument_route").GET("/**", http()) + .before(uri("https://example.org")) + .before(instrument("X-Request-Id")) + .build(); } } ---- @@ -213,6 +218,7 @@ In this case we simply add the header to the response and return it. [source,java] ---- import static SampleAfterFilterFunctions.instrument; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -221,10 +227,11 @@ class RouteConfiguration { @Bean public RouterFunction instrumentRoute() { - return route("instrument_route") - .GET("/**", http("https://example.org")) - .after(instrument("X-Response-Id")) - .build(); + return route("instrument_route") + .GET("/**", http()) + .before(uri("https://example.org")) + .after(instrument("X-Response-Id")) + .build(); } } ---- diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/RouterFunctionHolderFactory.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/RouterFunctionHolderFactory.java index dcebc7e7..6bc52a52 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/RouterFunctionHolderFactory.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/RouterFunctionHolderFactory.java @@ -39,7 +39,6 @@ import org.springframework.boot.context.properties.source.ConfigurationPropertyS import org.springframework.boot.context.properties.source.MapConfigurationPropertySource; import org.springframework.cloud.gateway.server.mvc.common.Configurable; import org.springframework.cloud.gateway.server.mvc.common.MvcUtils; -import org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions; import org.springframework.cloud.gateway.server.mvc.filter.FilterDiscoverer; import org.springframework.cloud.gateway.server.mvc.handler.HandlerDiscoverer; import org.springframework.cloud.gateway.server.mvc.invoke.InvocationContext; @@ -150,15 +149,6 @@ public class RouterFunctionHolderFactory { RouterFunctions.Builder builder = route(routeId); - // MVC.fn users won't need this anonymous filter as url will be set directly. - // Put this function first, so if a filter from a handler changes the url - // it is after this one. - builder.filter((request, next) -> { - MvcUtils.setRequestUrl(request, routeProperties.getUri()); - return next.handle(request); - }); - builder.before(BeforeFilterFunctions.routeId(routeId)); - MultiValueMap handlerOperations = handlerDiscoverer.getOperations(); // TODO: cache? // translate handlerFunction @@ -181,13 +171,15 @@ public class RouterFunctionHolderFactory { HandlerFunction handlerFunction = null; // filters added by HandlerDiscoverer need to go last, so save them - List> handlerFilterFunctionFilters = new ArrayList<>(); + List> lowerPrecedenceFilters = new ArrayList<>(); + List> higherPrecedenceFilters = new ArrayList<>(); if (response instanceof HandlerFunction) { handlerFunction = (HandlerFunction) response; } else if (response instanceof HandlerDiscoverer.Result result) { handlerFunction = result.getHandlerFunction(); - handlerFilterFunctionFilters.addAll(result.getFilters()); + lowerPrecedenceFilters.addAll(result.getLowerPrecedenceFilters()); + higherPrecedenceFilters.addAll(result.getHigherPrecedenceFilters()); } if (handlerFunction == null) { throw new IllegalStateException( @@ -218,6 +210,9 @@ public class RouterFunctionHolderFactory { builder.route(predicate.get(), handlerFunction); predicate.set(null); + // HandlerDiscoverer filters needing lower priority, so put them first + lowerPrecedenceFilters.forEach(builder::filter); + // translate filters MultiValueMap filterOperations = filterDiscoverer.getOperations(); routeProperties.getFilters().forEach(filterProperties -> { @@ -226,7 +221,7 @@ public class RouterFunctionHolderFactory { }); // HandlerDiscoverer filters need higher priority, so put them last - handlerFilterFunctionFilters.forEach(builder::filter); + higherPrecedenceFilters.forEach(builder::filter); builder.withAttribute(MvcUtils.GATEWAY_ROUTE_ID_ATTR, routeId); diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java index dba4e260..0e95bf82 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java @@ -196,7 +196,6 @@ public abstract class BeforeFilterFunctions { String newPath = uri.getRawPath() + request.uri().getRawPath(); URI prefixedUri = UriComponentsBuilder.fromUri(request.uri()).replacePath(newPath).build().toUri(); - MvcUtils.setRequestUrl(request, prefixedUri); return ServerRequest.from(request).uri(prefixedUri).build(); }; } @@ -340,7 +339,6 @@ public abstract class BeforeFilterFunctions { ServerRequest modified = ServerRequest.from(request).uri(rewrittenUri).build(); - MvcUtils.setRequestUrl(request, rewrittenUri); return modified; }; } @@ -361,7 +359,6 @@ public abstract class BeforeFilterFunctions { URI uri = uriTemplate.expand(uriVariables); URI newUri = UriComponentsBuilder.fromUri(request.uri()).replacePath(uri.getRawPath()).build(true).toUri(); - MvcUtils.setRequestUrl(request, newUri); return ServerRequest.from(request).uri(newUri).build(); }; } @@ -419,12 +416,22 @@ public abstract class BeforeFilterFunctions { .replacePath(newPath.toString()) .build(true) .toUri(); - MvcUtils.setRequestUrl(request, prefixedUri); return ServerRequest.from(request).uri(prefixedUri).build(); }; } + public static Function uri(String uri) { + return uri(URI.create(uri)); + } + + public static Function uri(URI uri) { + return request -> { + MvcUtils.setRequestUrl(request, uri); + return request; + }; + } + public static class FallbackHeadersConfig { private String executionExceptionTypeHeaderName = CB_EXECUTION_EXCEPTION_TYPE; diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/FilterFunctions.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/FilterFunctions.java index c7cb910f..55b6602c 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/FilterFunctions.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/FilterFunctions.java @@ -228,6 +228,15 @@ public interface FilterFunctions { return ofResponseProcessor(AfterFilterFunctions.setStatus(statusCode)); } + static HandlerFilterFunction uri(String uri) { + return ofRequestProcessor(BeforeFilterFunctions.uri(uri)); + } + + @Shortcut + static HandlerFilterFunction uri(URI uri) { + return ofRequestProcessor(BeforeFilterFunctions.uri(uri)); + } + class FilterSupplier extends SimpleFilterSupplier { public FilterSupplier() { diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/LoadBalancerHandlerSupplier.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/LoadBalancerHandlerSupplier.java index 3cedfa35..c2a0ad58 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/LoadBalancerHandlerSupplier.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/LoadBalancerHandlerSupplier.java @@ -40,7 +40,7 @@ public class LoadBalancerHandlerSupplier implements HandlerSupplier { public static HandlerDiscoverer.Result lb(URI uri) { // TODO: how to do something other than http - return new HandlerDiscoverer.Result(HandlerFunctions.http(), + return new HandlerDiscoverer.Result(HandlerFunctions.http(), Collections.emptyList(), Collections.singletonList(LoadBalancerFilterFunctions.lb(uri.getHost()))); } diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/XForwardedRequestHeadersFilter.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/XForwardedRequestHeadersFilter.java index 9b8b9bcb..bee93756 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/XForwardedRequestHeadersFilter.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/XForwardedRequestHeadersFilter.java @@ -400,7 +400,7 @@ public class XForwardedRequestHeadersFilter implements HttpHeadersFilter.Request LinkedHashSet originalUris = MvcUtils.getAttribute(request, MvcUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR); - URI requestUri = MvcUtils.getAttribute(request, MvcUtils.GATEWAY_REQUEST_URL_ATTR); + URI requestUri = request.uri(); if (originalUris != null && requestUri != null) { diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/DefaultHandlerSupplier.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/DefaultHandlerSupplier.java new file mode 100644 index 00000000..91304f9f --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/DefaultHandlerSupplier.java @@ -0,0 +1,92 @@ +/* + * Copyright 2013-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.gateway.server.mvc.handler; + +import java.lang.reflect.Method; +import java.net.URI; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; + +import org.springframework.cloud.gateway.server.mvc.common.MvcUtils; +import org.springframework.cloud.gateway.server.mvc.config.RouteProperties; +import org.springframework.web.servlet.function.HandlerFilterFunction; +import org.springframework.web.servlet.function.HandlerFunction; +import org.springframework.web.servlet.function.ServerResponse; + +class DefaultHandlerSupplier implements HandlerSupplier { + + @Override + public Collection get() { + return Arrays.asList(getClass().getMethods()); + } + + public static HandlerDiscoverer.Result forward(RouteProperties routeProperties) { + return forward(routeProperties.getId(), routeProperties.getUri()); + } + + public static HandlerDiscoverer.Result forward(String id, URI uri) { + return new HandlerDiscoverer.Result(HandlerFunctions.forward(uri.getPath()), Collections.emptyList()); + } + + public static HandlerDiscoverer.Result http(RouteProperties routeProperties) { + return http(routeProperties.getId(), routeProperties.getUri()); + } + + public static HandlerDiscoverer.Result http(String id, URI uri) { + HandlerFunction http = HandlerFunctions.http(); + return getResult(id, uri, http); + } + + public static HandlerDiscoverer.Result https(RouteProperties routeProperties) { + return https(routeProperties.getId(), routeProperties.getUri()); + } + + public static HandlerDiscoverer.Result https(String id, URI uri) { + return getResult(id, uri, HandlerFunctions.https()); + } + + public static HandlerDiscoverer.Result no(RouteProperties routeProperties) { + return no(routeProperties.getId(), routeProperties.getUri()); + } + + public static HandlerDiscoverer.Result no(String id, URI uri) { + return getResult(id, uri, HandlerFunctions.no()); + } + + private static HandlerDiscoverer.Result getResult(String id, URI uri, + HandlerFunction handlerFunction) { + HandlerFilterFunction setId = setIdFilter(id); + HandlerFilterFunction setRequest = setRequestUrlFilter(uri); + return new HandlerDiscoverer.Result(handlerFunction, Arrays.asList(setId, setRequest), Collections.emptyList()); + } + + private static HandlerFilterFunction setIdFilter(String id) { + return (request, next) -> { + MvcUtils.setRouteId(request, id); + return next.handle(request); + }; + } + + private static HandlerFilterFunction setRequestUrlFilter(URI uri) { + return (request, next) -> { + MvcUtils.setRequestUrl(request, uri); + return next.handle(request); + }; + } + +} diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerDiscoverer.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerDiscoverer.java index be0dd7cf..7569842d 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerDiscoverer.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerDiscoverer.java @@ -37,20 +37,39 @@ public class HandlerDiscoverer extends AbstractGatewayDiscoverer { private final HandlerFunction handlerFunction; - private final List> filters; + private final List> lowerPrecedenceFilters; + private final List> higherPrecedenceFilters; + + @Deprecated public Result(HandlerFunction handlerFunction, List> filters) { + this(handlerFunction, Collections.emptyList(), filters); + } + + public Result(HandlerFunction handlerFunction, + List> lowerPrecedenceFilters, + List> higherPrecedenceFilters) { this.handlerFunction = handlerFunction; - this.filters = Objects.requireNonNullElse(filters, Collections.emptyList()); + this.lowerPrecedenceFilters = Objects.requireNonNullElse(lowerPrecedenceFilters, Collections.emptyList()); + this.higherPrecedenceFilters = Objects.requireNonNullElse(higherPrecedenceFilters, Collections.emptyList()); } public HandlerFunction getHandlerFunction() { return handlerFunction; } + @Deprecated public List> getFilters() { - return filters; + return getHigherPrecedenceFilters(); + } + + public List> getLowerPrecedenceFilters() { + return lowerPrecedenceFilters; + } + + public List> getHigherPrecedenceFilters() { + return higherPrecedenceFilters; } } diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctions.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctions.java index 9b3d118b..0b9f99ac 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctions.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctions.java @@ -19,8 +19,8 @@ package org.springframework.cloud.gateway.server.mvc.handler; import java.io.IOException; import java.lang.reflect.Method; import java.net.URI; -import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.concurrent.atomic.AtomicReference; import jakarta.servlet.ServletException; @@ -60,14 +60,17 @@ public abstract class HandlerFunctions { // TODO: current discovery only goes by method name // so last one wins, so put parameterless last + @Deprecated public static HandlerFunction http(String uri) { return http(URI.create(uri)); } + @Deprecated public static HandlerFunction http(URI uri) { return new LookupProxyExchangeHandlerFunction(uri); } + @Deprecated public static HandlerFunction https(URI uri) { return new LookupProxyExchangeHandlerFunction(uri); } @@ -86,6 +89,7 @@ public abstract class HandlerFunctions { static class LookupProxyExchangeHandlerFunction implements HandlerFunction { + @Deprecated private final URI uri; private AtomicReference proxyExchangeHandlerFunction = new AtomicReference<>(); @@ -94,6 +98,7 @@ public abstract class HandlerFunctions { this.uri = null; } + @Deprecated LookupProxyExchangeHandlerFunction(URI uri) { this.uri = uri; } @@ -101,12 +106,15 @@ public abstract class HandlerFunctions { @Override public ServerResponse handle(ServerRequest serverRequest) { if (uri != null) { - // TODO: in 2 places now, here and - // GatewayMvcPropertiesBeanDefinitionRegistrar - MvcUtils.putAttribute(serverRequest, MvcUtils.GATEWAY_REQUEST_URL_ATTR, uri); + // TODO: log warning of deprecated usage + MvcUtils.setRequestUrl(serverRequest, uri); } - this.proxyExchangeHandlerFunction.compareAndSet(null, lookup(serverRequest)); - return proxyExchangeHandlerFunction.get().handle(serverRequest); + return proxyExchangeHandlerFunction.updateAndGet(function -> { + if (function == null) { + return lookup(serverRequest); + } + return function; + }).handle(serverRequest); } private static ProxyExchangeHandlerFunction lookup(ServerRequest request) { @@ -124,12 +132,13 @@ public abstract class HandlerFunctions { } + @Deprecated public static class HandlerSupplier implements org.springframework.cloud.gateway.server.mvc.handler.HandlerSupplier { @Override public Collection get() { - return Arrays.asList(HandlerFunctions.class.getMethods()); + return Collections.emptyList(); } } diff --git a/spring-cloud-gateway-server-mvc/src/main/resources/META-INF/spring.factories b/spring-cloud-gateway-server-mvc/src/main/resources/META-INF/spring.factories index 4b1b5077..b2be9e16 100644 --- a/spring-cloud-gateway-server-mvc/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-gateway-server-mvc/src/main/resources/META-INF/spring.factories @@ -23,7 +23,7 @@ org.springframework.cloud.gateway.server.mvc.filter.FilterSupplier=\ org.springframework.cloud.gateway.server.mvc.filter.FilterFunctions.FilterSupplier org.springframework.cloud.gateway.server.mvc.handler.HandlerSupplier=\ - org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.HandlerSupplier,\ + org.springframework.cloud.gateway.server.mvc.handler.DefaultHandlerSupplier,\ org.springframework.cloud.gateway.server.mvc.filter.LoadBalancerHandlerSupplier org.springframework.cloud.gateway.server.mvc.predicate.PredicateSupplier=\ diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java index 4188d73a..aaf409af 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java @@ -76,6 +76,7 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.util.StreamUtils; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @@ -107,6 +108,7 @@ import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFu import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.requestHeaderToRequestUri; import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.requestSize; import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.routeId; +import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; import static org.springframework.cloud.gateway.server.mvc.filter.Bucket4jFilterFunctions.rateLimit; import static org.springframework.cloud.gateway.server.mvc.filter.CircuitBreakerFilterFunctions.circuitBreaker; import static org.springframework.cloud.gateway.server.mvc.filter.FilterFunctions.addRequestHeader; @@ -298,7 +300,7 @@ public class ServerMvcIntegrationTests { XForwardedRequestHeadersFilter.X_FORWARDED_FOR_HEADER); assertThat(headers).containsEntry(XForwardedRequestHeadersFilter.X_FORWARDED_PREFIX_HEADER, "/long/path/to"); - assertThat(headers).containsEntry("X-Test", "stripPrefix"); + assertThat(headers).containsEntry("X-Test", "stripPrefixLb"); }); } @@ -418,7 +420,8 @@ public class ServerMvcIntegrationTests { public void circuitBreakerInvalidFallbackThrowsException() { // @formatter:off Assertions.assertThatThrownBy(() -> route("testcircuitbreakergatewayfallback") - .route(path("/anything/circuitbreakergatewayfallback"), http(URI.create("https://nonexistantdomain.com1234"))) + .route(path("/anything/circuitbreakergatewayfallback"), http()) + .before(uri("https://nonexistantdomain.com1234")) .filter(circuitBreaker("mycb2", URI.create("http://example.com"))) .build()).isInstanceOf(IllegalArgumentException.class); // @formatter:on @@ -1016,6 +1019,11 @@ public class ServerMvcIntegrationTests { @LoadBalancerClient(name = "httpbin", configuration = TestLoadBalancerConfig.Httpbin.class) protected static class TestConfiguration { + @Bean + StaticPortController staticPortController() { + return new StaticPortController(); + } + @Bean TestHandler testHandler() { return new TestHandler(); @@ -1132,7 +1140,7 @@ public class ServerMvcIntegrationTests { return route("teststripprefix") .route(GET("/long/path/to/get").and(host("**.stripprefixlb.org")), http()) .filter(stripPrefix(3)) - .filter(addRequestHeader("X-Test", "stripPrefix")) + .filter(addRequestHeader("X-Test", "stripPrefixLb")) .filter(lb("httpbin")) .build(); // @formatter:on @@ -1185,7 +1193,8 @@ public class ServerMvcIntegrationTests { public RouterFunction gatewayRouterFunctionsCircuitBreakerFallback() { // @formatter:off return route("testcircuitbreakerfallback") - .route(path("/anything/circuitbreakerfallback"), http(URI.create("https://nonexistantdomain.com1234"))) + .route(path("/anything/circuitbreakerfallback"), http()) + .before(uri("https://nonexistantdomain.com1234")) .filter(circuitBreaker("mycb1", "/hello")) .build(); // @formatter:on @@ -1195,7 +1204,8 @@ public class ServerMvcIntegrationTests { public RouterFunction gatewayRouterFunctionsCircuitBreakerFallbackToGatewayRoute() { // @formatter:off return route("testcircuitbreakergatewayfallback") - .route(path("/anything/circuitbreakergatewayfallback"), http(URI.create("https://nonexistantdomain.com1234"))) + .route(path("/anything/circuitbreakergatewayfallback"), http()) + .before(uri("https://nonexistantdomain.com1234")) .filter(circuitBreaker("mycb2", URI.create("forward:/anything/gatewayfallback"))) .build() .and(route("testgatewayfallback") @@ -1686,6 +1696,16 @@ public class ServerMvcIntegrationTests { } + @RestController + protected static class StaticPortController { + + @GetMapping(path = "/anything/staticport", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity messageEvents() { + return ResponseEntity.status(HttpStatus.NOT_ACCEPTABLE).build(); + } + + } + @RestController protected static class EventController { diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java index ae6a7ee2..8c8a12ee 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java @@ -156,6 +156,18 @@ class BeforeFilterFunctionsTests { assertThat(result.uri().toString()).hasToString("http://localhost/depth3"); } + @Test + void stripPrefixWithPort() { + MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost:77/depth1/depth2/depth3") + .buildRequest(null); + + ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList()); + + ServerRequest result = BeforeFilterFunctions.stripPrefix(2).apply(request); + + assertThat(result.uri().toString()).hasToString("http://localhost:77/depth3"); + } + @Test void stripPrefixWithEncodedPath() { MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/depth1/depth2/depth3/é") diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/StripPrefixStaticPortTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/StripPrefixStaticPortTests.java new file mode 100644 index 00000000..4052a3f6 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/StripPrefixStaticPortTests.java @@ -0,0 +1,141 @@ +/* + * Copyright 2013-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.gateway.server.mvc.filter; + +import java.util.Map; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.cloud.gateway.server.mvc.test.HttpbinTestcontainers; +import org.springframework.cloud.gateway.server.mvc.test.TestLoadBalancerConfig; +import org.springframework.cloud.gateway.server.mvc.test.client.TestRestClient; +import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient; +import org.springframework.context.annotation.Bean; +import org.springframework.core.env.Environment; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.function.RouterFunction; +import org.springframework.web.servlet.function.ServerResponse; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.cloud.gateway.server.mvc.filter.FilterFunctions.stripPrefix; +import static org.springframework.cloud.gateway.server.mvc.filter.FilterFunctions.uri; +import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; +import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; +import static org.springframework.cloud.gateway.server.mvc.test.TestUtils.getMap; + +@SuppressWarnings("unchecked") +@SpringBootTest(properties = {}, webEnvironment = WebEnvironment.RANDOM_PORT) +@ActiveProfiles("stripprefixstaticport") +@ContextConfiguration(initializers = HttpbinTestcontainers.class) +public class StripPrefixStaticPortTests { + + @Autowired + TestRestClient restClient; + + @BeforeAll + static void beforeAll() { + HttpbinTestcontainers.initializeSystemProperties(); + } + + @Test + public void stripPrefixStaticPort() { + restClient.get() + .uri("/long/path/to/anything/staticport") + .exchange() + .expectStatus() + .isOk() + .expectBody(Map.class) + .consumeWith(res -> { + Map map = res.getResponseBody(); + Map headers = getMap(map, "headers"); + assertThat(headers) + .containsKeys(XForwardedRequestHeadersFilter.X_FORWARDED_PREFIX_HEADER, + XForwardedRequestHeadersFilter.X_FORWARDED_HOST_HEADER, + XForwardedRequestHeadersFilter.X_FORWARDED_PORT_HEADER, + XForwardedRequestHeadersFilter.X_FORWARDED_PROTO_HEADER, + XForwardedRequestHeadersFilter.X_FORWARDED_FOR_HEADER) + .containsEntry(XForwardedRequestHeadersFilter.X_FORWARDED_PREFIX_HEADER, "/long/path/to"); + }); + } + + @Test + public void stripPrefixStaticPortDsl() { + restClient.get() + .uri("/long/path/to/anything/staticportdsl") + .exchange() + .expectStatus() + .isOk() + .expectBody(Map.class) + .consumeWith(res -> { + Map map = res.getResponseBody(); + Map headers = getMap(map, "headers"); + assertThat(headers) + .containsKeys(XForwardedRequestHeadersFilter.X_FORWARDED_PREFIX_HEADER, + XForwardedRequestHeadersFilter.X_FORWARDED_HOST_HEADER, + XForwardedRequestHeadersFilter.X_FORWARDED_PORT_HEADER, + XForwardedRequestHeadersFilter.X_FORWARDED_PROTO_HEADER, + XForwardedRequestHeadersFilter.X_FORWARDED_FOR_HEADER) + .containsEntry(XForwardedRequestHeadersFilter.X_FORWARDED_PREFIX_HEADER, "/long/path/to"); + }); + } + + @SpringBootConfiguration + @EnableAutoConfiguration + @LoadBalancerClient(name = "httpbin", configuration = TestLoadBalancerConfig.Httpbin.class) + protected static class TestConfiguration { + + @Bean + StaticPortController staticPortController() { + return new StaticPortController(); + } + + @Bean + public RouterFunction gatewayRouterFunctionsStripPrefixStaticPortDsl(Environment env) { + // @formatter:off + return route("teststripprefixstaticportdsl") + .GET("/long/path/to/anything/staticportdsl", http()) + .filter(uri(env.getProperty("strip.prefix.static.uri"))) + .filter(stripPrefix(3)) + .build(); + // @formatter:on + } + + } + + @RestController + protected static class StaticPortController { + + @GetMapping(path = "/anything/staticport", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity messageEvents() { + return ResponseEntity.status(HttpStatus.NOT_ACCEPTABLE).build(); + } + + } + +} diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/test/HttpbinTestcontainers.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/test/HttpbinTestcontainers.java index e1dc98a4..95345fce 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/test/HttpbinTestcontainers.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/test/HttpbinTestcontainers.java @@ -18,8 +18,6 @@ package org.springframework.cloud.gateway.server.mvc.test; import java.util.HashMap; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; import org.testcontainers.utility.DockerImageName; @@ -35,8 +33,6 @@ public class HttpbinTestcontainers implements ApplicationContextInitializer map = new HashMap<>(); map.put("httpbin.port", String.valueOf(mappedPort)); diff --git a/spring-cloud-gateway-server-mvc/src/test/resources/application-stripprefixstaticport.yml b/spring-cloud-gateway-server-mvc/src/test/resources/application-stripprefixstaticport.yml new file mode 100644 index 00000000..c27795c3 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/test/resources/application-stripprefixstaticport.yml @@ -0,0 +1,12 @@ +strip.prefix.static.uri: http://${httpbin.host}:${httpbin.port} +spring.cloud.gateway.mvc: + routes: + - id: strip_prefix_static_port_config + uri: ${strip.prefix.static.uri} + predicates: + - Path=/long/path/to/anything/staticport + filters: + - StripPrefix=3 +logging: + level: + org.springframework.cloud.gateway.server.mvc: TRACE