For lb: scheme, put associated filters last.

This makes sure the lb filter runs after path modifying filters like stripPrefix.

See gh-3443
This commit is contained in:
spencergibb
2025-03-17 16:12:09 -04:00
parent b82da55fae
commit f6f90df404
8 changed files with 21 additions and 5 deletions

View File

@@ -43,6 +43,8 @@ spring:
- Path=/api/**
----
WARNING: If using the `lb()` filter, it needs to be after any filter that manipulates the path such as `setPath()` or `stripPrefix()`, otherwise the resulting url could be incorrect. The `lb:` scheme handler in configuration, automatically puts the filter in the highest precedence order.
NOTE: By default, when a service instance cannot be found by the `ReactorLoadBalancer`, a `503` is returned.
// TODO: implement use404
// You can configure the gateway to return a `404` by setting `spring.cloud.gateway.loadbalancer.use404=true`.

View File

@@ -33,7 +33,7 @@ class RouteConfiguration {
public RouterFunction<ServerResponse> gatewayRouterFunctionsPrefixPath() {
return route("prefixpath_route")
.GET("/**", http("https://example.org"))
.before("/mypath")
.before(prefixPath("/mypath"))
.build();
}
}
@@ -42,3 +42,4 @@ class RouteConfiguration {
This prefixes `/mypath` to the path of all matching requests.
So a request to `/hello` is sent to `/mypath/hello`.
WARNING: If using the `lb()` filter, it needs to be after the `prefixPath()` filter, otherwise the resulting url could be incorrect. The `lb:` scheme handler in configuration, automatically puts the filter in the highest precedence order.

View File

@@ -43,3 +43,4 @@ class RouteConfiguration {
For a request path of `/red/blue`, this sets the path to `/blue` before making the downstream request. Note that in `application.yml` the `$` should be replaced with `$\` because of the YAML specification.
WARNING: If using the `lb()` filter, it needs to be after the `rewritePath()` filter, otherwise the resulting url could be incorrect. The `lb:` scheme handler in configuration, automatically puts the filter in the highest precedence order.

View File

@@ -45,3 +45,4 @@ class RouteConfiguration {
For a request path of `/red/blue`, this sets the path to `/blue` before making the downstream request.
WARNING: If using the `lb()` filter, it needs to be after the `setPath()` filter, otherwise the resulting url could be incorrect. The `lb:` scheme handler in configuration, automatically puts the filter in the highest precedence order.

View File

@@ -43,3 +43,4 @@ class RouteConfiguration {
When a request is made through the gateway to `/name/blue/red`, the request made to `nameservice` looks like `https://nameservice/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.

View File

@@ -16,6 +16,7 @@
package org.springframework.cloud.gateway.server.mvc.config;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
@@ -178,12 +179,15 @@ public class RouterFunctionHolderFactory {
NormalizedOperationMethod normalizedOpMethod = handlerOperationMethod.get();
Object response = invokeOperation(normalizedOpMethod, normalizedOpMethod.getNormalizedArgs());
HandlerFunction<ServerResponse> handlerFunction = null;
// filters added by HandlerDiscoverer need to go last, so save them
List<HandlerFilterFunction<ServerResponse, ServerResponse>> handlerFilterFunctionFilters = new ArrayList<>();
if (response instanceof HandlerFunction<?>) {
handlerFunction = (HandlerFunction<ServerResponse>) response;
}
else if (response instanceof HandlerDiscoverer.Result result) {
handlerFunction = result.getHandlerFunction();
result.getFilters().forEach(builder::filter);
handlerFilterFunctionFilters.addAll(result.getFilters());
}
if (handlerFunction == null) {
throw new IllegalStateException(
@@ -221,6 +225,9 @@ public class RouterFunctionHolderFactory {
translate(filterOperations, filterProperties.getName(), args, HandlerFilterFunction.class, builder::filter);
});
// HandlerDiscoverer filters need higher priority, so put them last
handlerFilterFunctionFilters.forEach(builder::filter);
builder.withAttribute(MvcUtils.GATEWAY_ROUTE_ID_ATTR, routeId);
return builder.build();

View File

@@ -122,7 +122,7 @@ public class GatewayMvcPropertiesBeanDefinitionRegistrarTests {
predicate.accept(new AbstractRequestPredicatesVisitor() {
@Override
public void path(String pattern) {
assertThat(pattern).isEqualTo("/anything/listRoute3");
assertThat(pattern).isEqualTo("/extra/anything/listRoute3");
}
@Override
@@ -181,7 +181,7 @@ public class GatewayMvcPropertiesBeanDefinitionRegistrarTests {
@SuppressWarnings("unchecked")
public void lbRouteWorks() {
restClient.get()
.uri("/anything/listRoute3")
.uri("/extra/anything/listRoute3")
.header("MyHeaderName", "MyHeaderVal")
.exchange()
.expectStatus()

View File

@@ -38,9 +38,12 @@ spring.cloud.gateway.mvc:
- id: listRoute3
uri: lb://httpbin
predicates:
- Path=/anything/listRoute3
- Path=/extra/anything/listRoute3
- Header=MyHeaderName,MyHeader.*
filters:
- name: StripPrefix
args:
parts: 1
- name: AddRequestHeader
args:
name: X-Test