This commit is contained in:
Abel Salgado Romero
2022-09-27 19:51:18 +02:00
parent f998ca4f75
commit f45d03ec1d
3 changed files with 178 additions and 129 deletions

View File

@@ -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.

View File

@@ -7,6 +7,8 @@ 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 {
@@ -14,10 +16,10 @@ public class KeyValueConverter implements Converter<String, KeyValue> {
if (source.contains(":") && StringUtils.hasText(split[0])) {
return new KeyValue(split[0], split.length == 1 ? "" : split[1]);
}
throw new IllegalArgumentException("Invalid configuration, expected format is: 'key:value'");
throw new IllegalArgumentException(INVALID_CONFIGURATION_MESSAGE);
}
catch (ArrayIndexOutOfBoundsException e) {
throw new IllegalArgumentException("Invalid configuration, expected format is: 'key:value'");
throw new IllegalArgumentException(INVALID_CONFIGURATION_MESSAGE);
}
}

View File

@@ -1,127 +1,127 @@
///*
// * 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.route.builder
//
//import org.junit.Test
//import org.junit.runner.RunWith
//import org.springframework.beans.factory.annotation.Autowired
//import org.springframework.boot.autoconfigure.EnableAutoConfiguration
//import org.springframework.boot.test.context.SpringBootTest
//import org.springframework.cloud.gateway.support.ServerWebExchangeUtils
//import org.springframework.context.annotation.Configuration
//import org.springframework.mock.http.server.reactive.MockServerHttpRequest
//import org.springframework.mock.web.server.MockServerWebExchange
//import org.springframework.test.context.junit4.SpringRunner
//import org.springframework.web.server.ServerWebExchange
//import reactor.core.publisher.toMono
//import reactor.test.StepVerifier
//import java.net.URI
//
//@RunWith(SpringRunner::class)
//@SpringBootTest(classes = arrayOf(Config::class))
//class RouteDslTests {
//
// @Autowired
// lateinit var builder: RouteLocatorBuilder
//
// @Test
// fun sampleRouteDsl() {
// val routeLocator = builder.routes {
// route(id = "test") {
// host("**.abc.org") and path("/image/png")
// filters {
// addResponseHeader("X-TestHeader", "foobar")
// }
// uri("http://httpbin.org:80")
// }
//
// route(id = "test2") {
// path("/image/webp") or path("/image/anotherone")
// filters {
// addResponseHeader("X-AnotherHeader", "baz")
// addResponseHeader("X-AnotherHeader-2", "baz-2")
// }
// uri("https://httpbin.org:443")
// }
// }
//
// StepVerifier
// .create(routeLocator.routes)
// .expectNextMatches({
// it.id == "test" && it.filters.size == 1 && it.uri == URI.create("http://httpbin.org:80")
// })
// .expectNextMatches({
// it.id == "test2" && it.filters.size == 2 && it.uri == URI.create("https://httpbin.org:443")
// })
// .expectComplete()
// .verify()
//
// val sampleExchange: ServerWebExchange = MockServerWebExchange.from(MockServerHttpRequest.get("/image/webp")
// .header("Host", "test.abc.org").build())
//
// val filteredRoutes = routeLocator.routes.filter({
// sampleExchange.attributes.put(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR, it.id)
// it.predicate.apply(sampleExchange).toMono().block()
// })
//
// StepVerifier.create(filteredRoutes)
// .expectNextMatches({
// it.id == "test2" && it.filters.size == 2 && it.uri == URI.create("https://httpbin.org:443")
// })
// .expectComplete()
// .verify()
// }
//
// @Test
// fun dslWithFunctionParameters() {
// val routerLocator = builder.routes {
// route(id = "test1", order = 10, uri = "http://httpbin.org") {
// host("**.abc.org")
// }
// route(id = "test2", order = 10, uri = "http://someurl") {
// host("**.abc.org")
// uri("http://override-url")
// }
// }
//
// StepVerifier.create(routerLocator.routes)
// .expectNextMatches({
// it.id == "test1" &&
// it.uri == URI.create("http://httpbin.org:80") &&
// it.order == 10 &&
// it.predicate.apply(MockServerWebExchange
// .from(MockServerHttpRequest
// .get("/someuri").header("Host", "test.abc.org")))
// .toMono().block()
// })
// .expectNextMatches({
// it.id == "test2" &&
// it.uri == URI.create("http://override-url:80") &&
// it.order == 10 &&
// it.predicate.apply(MockServerWebExchange
// .from(MockServerHttpRequest
// .get("/someuri").header("Host", "test.abc.org")))
// .toMono().block()
// })
// .expectComplete()
// .verify()
// }
//}
//
//@Configuration(proxyBeanMethods = false)
//@EnableAutoConfiguration
//open class Config {}
/*
* 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.route.builder
import org.junit.Test
import org.junit.runner.RunWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils
import org.springframework.context.annotation.Configuration
import org.springframework.mock.http.server.reactive.MockServerHttpRequest
import org.springframework.mock.web.server.MockServerWebExchange
import org.springframework.test.context.junit4.SpringRunner
import org.springframework.web.server.ServerWebExchange
import reactor.core.publisher.toMono
import reactor.test.StepVerifier
import java.net.URI
@RunWith(SpringRunner::class)
@SpringBootTest(classes = arrayOf(Config::class))
class RouteDslTests {
@Autowired
lateinit var builder: RouteLocatorBuilder
@Test
fun sampleRouteDsl() {
val routeLocator = builder.routes {
route(id = "test") {
host("**.abc.org") and path("/image/png")
filters {
addResponseHeader("X-TestHeader", "foobar")
}
uri("http://httpbin.org:80")
}
route(id = "test2") {
path("/image/webp") or path("/image/anotherone")
filters {
addResponseHeader("X-AnotherHeader", "baz")
addResponseHeader("X-AnotherHeader-2", "baz-2")
}
uri("https://httpbin.org:443")
}
}
StepVerifier
.create(routeLocator.routes)
.expectNextMatches({
it.id == "test" && it.filters.size == 1 && it.uri == URI.create("http://httpbin.org:80")
})
.expectNextMatches({
it.id == "test2" && it.filters.size == 2 && it.uri == URI.create("https://httpbin.org:443")
})
.expectComplete()
.verify()
val sampleExchange: ServerWebExchange = MockServerWebExchange.from(MockServerHttpRequest.get("/image/webp")
.header("Host", "test.abc.org").build())
val filteredRoutes = routeLocator.routes.filter({
sampleExchange.attributes.put(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR, it.id)
it.predicate.apply(sampleExchange).toMono().block()
})
StepVerifier.create(filteredRoutes)
.expectNextMatches({
it.id == "test2" && it.filters.size == 2 && it.uri == URI.create("https://httpbin.org:443")
})
.expectComplete()
.verify()
}
@Test
fun dslWithFunctionParameters() {
val routerLocator = builder.routes {
route(id = "test1", order = 10, uri = "http://httpbin.org") {
host("**.abc.org")
}
route(id = "test2", order = 10, uri = "http://someurl") {
host("**.abc.org")
uri("http://override-url")
}
}
StepVerifier.create(routerLocator.routes)
.expectNextMatches({
it.id == "test1" &&
it.uri == URI.create("http://httpbin.org:80") &&
it.order == 10 &&
it.predicate.apply(MockServerWebExchange
.from(MockServerHttpRequest
.get("/someuri").header("Host", "test.abc.org")))
.toMono().block()
})
.expectNextMatches({
it.id == "test2" &&
it.uri == URI.create("http://override-url:80") &&
it.order == 10 &&
it.predicate.apply(MockServerWebExchange
.from(MockServerHttpRequest
.get("/someuri").header("Host", "test.abc.org")))
.toMono().block()
})
.expectComplete()
.verify()
}
}
@Configuration(proxyBeanMethods = false)
@EnableAutoConfiguration
open class Config {}