Merge branch 'add-AddRequestHeadersIfNotPresentGatewayFilterFactory-2359'
This commit is contained in:
@@ -534,6 +534,53 @@ spring:
|
||||
----
|
||||
====
|
||||
|
||||
=== The `AddRequestHeadersIfNotPresent` `GatewayFilter` Factory
|
||||
|
||||
The `AddRequestHeadersIfNotPresent` `GatewayFilter` factory takes a collection of `name` and `value` pairs separated by colon.
|
||||
The following example configures an `AddRequestHeadersIfNotPresent` `GatewayFilter`:
|
||||
|
||||
.application.yml
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
spring:
|
||||
cloud:
|
||||
gateway:
|
||||
routes:
|
||||
- id: add_request_headers_route
|
||||
uri: https://example.org
|
||||
filters:
|
||||
- AddRequestHeadersIfNotPresent=X-Request-Color-1:blue,X-Request-Color-2:green
|
||||
----
|
||||
====
|
||||
|
||||
This listing adds 2 headers `X-Request-Color-1:blue` and `X-Request-Color-2:green` to the downstream request's headers for all matching requests.
|
||||
This is similar to how `AddRequestHeader` works, but unlike `AddRequestHeader` it will do it only if the header is not already there.
|
||||
Otherwise, the original value in the client request is sent.
|
||||
|
||||
Additionally, to set a multi-valued header, use the header name multiple times like `AddRequestHeadersIfNotPresent=X-Request-Color-1:blue,X-Request-Color-1:green`.
|
||||
|
||||
`AddRequestHeadersIfNotPresent` also supports URI variables used to match a path or host.
|
||||
URI variables may be used in the value and are expanded at runtime.
|
||||
The following example configures an `AddRequestHeadersIfNotPresent` `GatewayFilter` that uses a variable:
|
||||
|
||||
.application.yml
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
spring:
|
||||
cloud:
|
||||
gateway:
|
||||
routes:
|
||||
- id: add_request_header_route
|
||||
uri: https://example.org
|
||||
predicates:
|
||||
- Path=/red/{segment}
|
||||
filters:
|
||||
- AddRequestHeadersIfNotPresent=X-Request-Red:Blue-{segment}
|
||||
----
|
||||
====
|
||||
|
||||
=== The `AddRequestParameter` `GatewayFilter` Factory
|
||||
|
||||
The `AddRequestParameter` `GatewayFilter` Factory takes a `name` and `value` parameter.
|
||||
|
||||
@@ -68,6 +68,7 @@ import org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter;
|
||||
import org.springframework.cloud.gateway.filter.WebsocketRoutingFilter;
|
||||
import org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter;
|
||||
import org.springframework.cloud.gateway.filter.factory.AddRequestHeaderGatewayFilterFactory;
|
||||
import org.springframework.cloud.gateway.filter.factory.AddRequestHeadersIfNotPresentGatewayFilterFactory;
|
||||
import org.springframework.cloud.gateway.filter.factory.AddRequestParameterGatewayFilterFactory;
|
||||
import org.springframework.cloud.gateway.filter.factory.AddResponseHeaderGatewayFilterFactory;
|
||||
import org.springframework.cloud.gateway.filter.factory.CacheRequestBodyGatewayFilterFactory;
|
||||
@@ -143,6 +144,7 @@ import org.springframework.cloud.gateway.route.RouteLocator;
|
||||
import org.springframework.cloud.gateway.route.RouteRefreshListener;
|
||||
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
|
||||
import org.springframework.cloud.gateway.support.ConfigurationService;
|
||||
import org.springframework.cloud.gateway.support.KeyValueConverter;
|
||||
import org.springframework.cloud.gateway.support.StringToZonedDateTimeConverter;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
@@ -187,6 +189,11 @@ public class GatewayAutoConfiguration {
|
||||
return new StringToZonedDateTimeConverter();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public KeyValueConverter keyValueConverter() {
|
||||
return new KeyValueConverter();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RouteLocatorBuilder routeLocatorBuilder(ConfigurableApplicationContext context) {
|
||||
return new RouteLocatorBuilder(context);
|
||||
@@ -473,6 +480,12 @@ public class GatewayAutoConfiguration {
|
||||
return new AddRequestHeaderGatewayFilterFactory();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnEnabledFilter
|
||||
public AddRequestHeadersIfNotPresentGatewayFilterFactory addRequestHeadersIfNotPresentGatewayFilterFactory() {
|
||||
return new AddRequestHeadersIfNotPresentGatewayFilterFactory();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnEnabledFilter
|
||||
public MapRequestHeaderGatewayFilterFactory mapRequestHeaderGatewayFilterFactory() {
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright 2013-2022 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.filter.factory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.cloud.gateway.filter.GatewayFilter;
|
||||
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator;
|
||||
|
||||
/**
|
||||
* Adds one or more headers to the downstream request’s headers without overriding
|
||||
* previous values. If the header is are already present, value(s) will not be set.
|
||||
*
|
||||
* @author Abel Salgado Romero
|
||||
*/
|
||||
public class AddRequestHeadersIfNotPresentGatewayFilterFactory
|
||||
extends AbstractGatewayFilterFactory<AddRequestHeadersIfNotPresentGatewayFilterFactory.KeyValueConfig> {
|
||||
|
||||
@Override
|
||||
public GatewayFilter apply(KeyValueConfig config) {
|
||||
return new GatewayFilter() {
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
||||
ServerHttpRequest.Builder requestBuilder = null;
|
||||
|
||||
Map<String, List<String>> aggregatedHeaders = new HashMap<>();
|
||||
|
||||
for (KeyValue keyValue : config.getKeyValues()) {
|
||||
String key = keyValue.getKey();
|
||||
List<String> candidateValue = aggregatedHeaders.get(key);
|
||||
if (candidateValue == null) {
|
||||
candidateValue = new ArrayList<>();
|
||||
candidateValue.add(keyValue.getValue());
|
||||
}
|
||||
else {
|
||||
candidateValue.add(keyValue.getValue());
|
||||
}
|
||||
aggregatedHeaders.put(key, candidateValue);
|
||||
}
|
||||
|
||||
for (Map.Entry<String, List<String>> kv : aggregatedHeaders.entrySet()) {
|
||||
String headerName = kv.getKey();
|
||||
|
||||
boolean headerIsMissingOrBlank = exchange.getRequest().getHeaders().getOrEmpty(headerName).stream()
|
||||
.allMatch(h -> !StringUtils.hasText(h));
|
||||
|
||||
if (headerIsMissingOrBlank) {
|
||||
if (requestBuilder == null) {
|
||||
requestBuilder = exchange.getRequest().mutate();
|
||||
}
|
||||
ServerWebExchange finalExchange = exchange;
|
||||
requestBuilder.headers(httpHeaders -> {
|
||||
List<String> replacedValues = kv.getValue().stream()
|
||||
.map(value -> ServerWebExchangeUtils.expand(finalExchange, value))
|
||||
.collect(Collectors.toList());
|
||||
httpHeaders.addAll(headerName, replacedValues);
|
||||
});
|
||||
}
|
||||
}
|
||||
if (requestBuilder != null) {
|
||||
exchange = exchange.mutate().request(requestBuilder.build()).build();
|
||||
}
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
ToStringCreator toStringCreator = filterToStringCreator(
|
||||
AddRequestHeadersIfNotPresentGatewayFilterFactory.this);
|
||||
for (KeyValue keyValue : config.getKeyValues()) {
|
||||
toStringCreator.append(keyValue.getKey(), keyValue.getValue());
|
||||
}
|
||||
return toStringCreator.toString();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public ShortcutType shortcutType() {
|
||||
return ShortcutType.GATHER_LIST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> shortcutFieldOrder() {
|
||||
return Collections.singletonList("keyValues");
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyValueConfig newConfig() {
|
||||
return new KeyValueConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<KeyValueConfig> getConfigClass() {
|
||||
return KeyValueConfig.class;
|
||||
}
|
||||
|
||||
public static class KeyValueConfig {
|
||||
|
||||
private KeyValue[] keyValues;
|
||||
|
||||
public KeyValue[] getKeyValues() {
|
||||
return keyValues;
|
||||
}
|
||||
|
||||
public void setKeyValues(KeyValue[] keyValues) {
|
||||
this.keyValues = keyValues;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class KeyValue {
|
||||
|
||||
private final String key;
|
||||
|
||||
private final String value;
|
||||
|
||||
public KeyValue(String key, String value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringCreator(this).append("name", key).append("value", value).toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,6 +19,7 @@ package org.springframework.cloud.gateway.route.builder;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@@ -37,6 +38,8 @@ import org.springframework.cloud.gateway.filter.GatewayFilter;
|
||||
import org.springframework.cloud.gateway.filter.OrderedGatewayFilter;
|
||||
import org.springframework.cloud.gateway.filter.factory.AbstractChangeRequestUriGatewayFilterFactory;
|
||||
import org.springframework.cloud.gateway.filter.factory.AddRequestHeaderGatewayFilterFactory;
|
||||
import org.springframework.cloud.gateway.filter.factory.AddRequestHeadersIfNotPresentGatewayFilterFactory;
|
||||
import org.springframework.cloud.gateway.filter.factory.AddRequestHeadersIfNotPresentGatewayFilterFactory.KeyValue;
|
||||
import org.springframework.cloud.gateway.filter.factory.AddRequestParameterGatewayFilterFactory;
|
||||
import org.springframework.cloud.gateway.filter.factory.AddResponseHeaderGatewayFilterFactory;
|
||||
import org.springframework.cloud.gateway.filter.factory.CacheRequestBodyGatewayFilterFactory;
|
||||
@@ -165,6 +168,20 @@ public class GatewayFilterSpec extends UriSpec {
|
||||
.apply(c -> c.setName(headerName).setValue(headerValue)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a request header to the request before it is routed by the Gateway.
|
||||
* @param headers the header name(s) and value(s) as
|
||||
* 'name-1:value-1,name-2:value-2,...'
|
||||
* @return a {@link GatewayFilterSpec} that can be used to apply additional filters
|
||||
*/
|
||||
public GatewayFilterSpec addRequestHeadersIfNotPresent(String... headers) {
|
||||
return filter(getBean(AddRequestHeadersIfNotPresentGatewayFilterFactory.class).apply(c -> {
|
||||
KeyValue[] values = Arrays.stream(headers).map(header -> header.split(":"))
|
||||
.map(parts -> new KeyValue(parts[0], parts[1])).toArray(size -> new KeyValue[size]);
|
||||
c.setKeyValues(values);
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a request parameter to the request before it is routed by the Gateway.
|
||||
* @param param the parameter name
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2013-2022 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.support;
|
||||
|
||||
import org.springframework.cloud.gateway.filter.factory.AddRequestHeadersIfNotPresentGatewayFilterFactory.KeyValue;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
public class KeyValueConverter implements Converter<String, KeyValue> {
|
||||
|
||||
private static final String INVALID_CONFIGURATION_MESSAGE = "Invalid configuration, expected format is: 'key:value'";
|
||||
|
||||
@Override
|
||||
public KeyValue convert(String source) throws IllegalArgumentException {
|
||||
try {
|
||||
String[] split = source.split(":");
|
||||
if (source.contains(":") && StringUtils.hasText(split[0])) {
|
||||
return new KeyValue(split[0], split.length == 1 ? "" : split[1]);
|
||||
}
|
||||
throw new IllegalArgumentException(INVALID_CONFIGURATION_MESSAGE);
|
||||
}
|
||||
catch (ArrayIndexOutOfBoundsException e) {
|
||||
throw new IllegalArgumentException(INVALID_CONFIGURATION_MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -80,6 +80,7 @@ public class DisableBuiltInFiltersTests {
|
||||
@SpringBootTest(classes = Config.class,
|
||||
properties = { "spring.cloud.gateway.filter.add-request-header.enabled=false",
|
||||
"spring.cloud.gateway.filter.map-request-header.enabled=false",
|
||||
"spring.cloud.gateway.filter.add-request-headers-if-not-present.enabled=false",
|
||||
"spring.cloud.gateway.filter.add-request-parameter.enabled=false",
|
||||
"spring.cloud.gateway.filter.add-response-header.enabled=false",
|
||||
"spring.cloud.gateway.filter.json-to-grpc.enabled=false",
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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.filter.factory;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.gateway.filter.GatewayFilter;
|
||||
import org.springframework.cloud.gateway.filter.factory.AddRequestHeadersIfNotPresentGatewayFilterFactory.KeyValue;
|
||||
import org.springframework.cloud.gateway.filter.factory.AddRequestHeadersIfNotPresentGatewayFilterFactory.KeyValueConfig;
|
||||
import org.springframework.cloud.gateway.route.RouteLocator;
|
||||
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
|
||||
import org.springframework.cloud.gateway.test.BaseWebClientTests;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
|
||||
import static org.springframework.cloud.gateway.test.TestUtils.getMap;
|
||||
|
||||
@SpringBootTest(webEnvironment = RANDOM_PORT)
|
||||
@DirtiesContext
|
||||
@ActiveProfiles(profiles = "request-headers-if-not-present-web-filter")
|
||||
public class AddRequestHeadersIfNotPresentGatewayFilterFactoryTests extends BaseWebClientTests {
|
||||
|
||||
private static final String TEST_HEADER_1 = "X-Request-Example";
|
||||
|
||||
private static final String TEST_HEADER_2 = "X-Request-Second-Example";
|
||||
|
||||
private static final String TEST_HOST_HEADER_VALUE = "www.addrequestheaderjava.org";
|
||||
|
||||
@Test
|
||||
public void addRequestHeadersIfHeaderPresentFilterDoesNotAddHeaderIfPresent() {
|
||||
final String initialHeaderValue = "initial-value";
|
||||
testClient.get().uri("/headers").header(TEST_HEADER_1, initialHeaderValue).exchange().expectBody(Map.class)
|
||||
.consumeWith(result -> {
|
||||
Map<String, Object> headers = getMap(result.getResponseBody(), "headers");
|
||||
assertThat(headers).containsEntry(TEST_HEADER_1, initialHeaderValue);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addRequestHeadersIfNotPresentFilterWorks() {
|
||||
testClient.get().uri("/headers").exchange().expectBody(Map.class).consumeWith(result -> {
|
||||
Map<String, Object> headers = getMap(result.getResponseBody(), "headers");
|
||||
assertThat(headers).containsEntry(TEST_HEADER_1, "ValueA");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addRequestHeadersIfNotPresentFilterOnlyWorksFirstPassWhenMultipleValues() {
|
||||
testClient.get().uri("/multivalueheaders").exchange().expectBody(Map.class).consumeWith(result -> {
|
||||
Map<String, Object> headers = getMap(result.getResponseBody(), "headers");
|
||||
assertThat(headers).containsEntry(TEST_HEADER_1, Arrays.asList("ValueA"));
|
||||
assertThat(headers).containsEntry(TEST_HEADER_2, Arrays.asList("ValueC"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addRequestHeadersIfNotPresentFilterWorksOnlyMissingValues() {
|
||||
final String existingValue = "existing-value";
|
||||
testClient.get().uri("/multivalueheaders").header(TEST_HEADER_2, existingValue).exchange().expectBody(Map.class)
|
||||
.consumeWith(result -> {
|
||||
Map<String, Object> headers = getMap(result.getResponseBody(), "headers");
|
||||
assertThat(headers).containsEntry(TEST_HEADER_1, Arrays.asList("ValueA"));
|
||||
assertThat(headers).containsEntry(TEST_HEADER_2, Arrays.asList(existingValue));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addRequestHeadersIfNotPresentFilterWorksJavaDsl() {
|
||||
testClient.get().uri("/headers").header("Host", TEST_HOST_HEADER_VALUE).exchange().expectBody(Map.class)
|
||||
.consumeWith(result -> {
|
||||
Map<String, Object> headers = getMap(result.getResponseBody(), "headers");
|
||||
assertThat(headers).containsEntry("X-Request-Acme", "ValueB-www");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addRequestHeadersIfNotPresentFilterMultipleValuesWorksJavaDsl() {
|
||||
testClient.get().uri("/multivalueheaders").header("Host", TEST_HOST_HEADER_VALUE).exchange()
|
||||
.expectBody(Map.class).consumeWith(result -> {
|
||||
Map<String, Object> headers = getMap(result.getResponseBody(), "headers");
|
||||
assertThat(headers).containsEntry("X-Request-Acme",
|
||||
Arrays.asList("ValueX", "ValueY", "ValueZ", "www"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toStringFormat() {
|
||||
KeyValueConfig keyValueConfig = new KeyValueConfig();
|
||||
keyValueConfig.setKeyValues(new KeyValue[] { new KeyValue("my-header-name-1", "my-header-value-1"),
|
||||
new KeyValue("my-header-name-2", "my-header-value-2"), });
|
||||
GatewayFilter filter = new AddRequestHeadersIfNotPresentGatewayFilterFactory().apply(keyValueConfig);
|
||||
assertThat(filter.toString()).startsWith("[AddRequestHeadersIfNotPresent")
|
||||
.contains("my-header-name-1 = 'my-header-value-1'").contains("my-header-name-2 = 'my-header-value-2'")
|
||||
.endsWith("]");
|
||||
}
|
||||
|
||||
@EnableAutoConfiguration
|
||||
@SpringBootConfiguration
|
||||
@Import(DefaultTestConfig.class)
|
||||
public static class TestConfig {
|
||||
|
||||
@Value("${test.uri}")
|
||||
String uri;
|
||||
|
||||
@Bean
|
||||
public RouteLocator testRouteLocator(RouteLocatorBuilder builder) {
|
||||
return builder.routes().route("add_request_headers_if_not_present_java_test",
|
||||
r -> r.path("/headers").and().host("{sub}.addrequestheaderjava.org")
|
||||
.filters(f -> f.addRequestHeadersIfNotPresent("X-Request-Acme:ValueB-{sub}")).uri(uri))
|
||||
.route("add_multiple_request_headers_java_test",
|
||||
r -> r.path("/multivalueheaders").and().host("{sub}.addrequestheaderjava.org")
|
||||
.filters(f -> f.addRequestHeadersIfNotPresent("X-Request-Acme:ValueX",
|
||||
"X-Request-Acme:ValueY", "X-Request-Acme:ValueZ", "X-Request-Acme:{sub}"))
|
||||
.uri(uri))
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
spring:
|
||||
cloud:
|
||||
gateway:
|
||||
routes:
|
||||
- id: add_request_headers_if_not_present_test
|
||||
uri: ${test.uri}
|
||||
predicates:
|
||||
- Path=/headers
|
||||
filters:
|
||||
- AddRequestHeadersIfNotPresent=X-Request-Example:ValueA
|
||||
- id: add_multiple_requests_if_not_present_header_test
|
||||
uri: ${test.uri}
|
||||
predicates:
|
||||
- Path=/multivalueheaders
|
||||
filters:
|
||||
- AddRequestHeadersIfNotPresent=X-Request-Example:ValueA,X-Request-Second-Example:ValueC
|
||||
- AddRequestHeadersIfNotPresent=X-Request-Example:ValueB,X-Request-Second-Example:ValueD
|
||||
Reference in New Issue
Block a user