Merge branch '4.2.x'
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
[[addresponseheader-gatewayfilter-factory]]
|
||||
= `AddResponseHeader` `GatewayFilter` Factory
|
||||
|
||||
The `AddResponseHeader` `GatewayFilter` Factory takes a `name` and `value` parameter.
|
||||
The `AddResponseHeader` `GatewayFilter` Factory takes three parameters: `name`, `value` and `override`(default value is `true`) .
|
||||
The following example configures an `AddResponseHeader` `GatewayFilter`:
|
||||
|
||||
.application.yml
|
||||
@@ -15,9 +15,12 @@ spring:
|
||||
uri: https://example.org
|
||||
filters:
|
||||
- AddResponseHeader=X-Response-Red, Blue
|
||||
- AddResponseHeader=X-Response-Black, White, false
|
||||
----
|
||||
|
||||
This adds `X-Response-Red:Blue` header to the downstream response's headers for all matching requests.
|
||||
and if the response already contains the `X-Response-Black` header, this will not add the `X-Response-Black: White`
|
||||
header to the downstream response's headers for all matching requests.
|
||||
|
||||
`AddResponseHeader` is aware of URI variables used to match a path or host.
|
||||
URI variables may be used in the value and are expanded at runtime.
|
||||
|
||||
@@ -16,12 +16,17 @@
|
||||
|
||||
package org.springframework.cloud.gateway.filter.factory;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
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.HttpHeaders;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator;
|
||||
@@ -31,6 +36,23 @@ import static org.springframework.cloud.gateway.support.GatewayToStringStyler.fi
|
||||
*/
|
||||
public class AddResponseHeaderGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
|
||||
|
||||
private static final String OVERRIDE_KEY = "override";
|
||||
|
||||
@Override
|
||||
public Class getConfigClass() {
|
||||
return Config.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NameValueConfig newConfig() {
|
||||
return new Config();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> shortcutFieldOrder() {
|
||||
return Arrays.asList(GatewayFilter.NAME_KEY, GatewayFilter.VALUE_KEY, OVERRIDE_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GatewayFilter apply(NameValueConfig config) {
|
||||
return new GatewayFilter() {
|
||||
@@ -41,6 +63,13 @@ public class AddResponseHeaderGatewayFilterFactory extends AbstractNameValueGate
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (config instanceof Config) {
|
||||
return filterToStringCreator(AddResponseHeaderGatewayFilterFactory.this)
|
||||
.append(GatewayFilter.NAME_KEY, config.getName())
|
||||
.append(GatewayFilter.VALUE_KEY, config.getValue())
|
||||
.append(OVERRIDE_KEY, ((Config) config).isOverride())
|
||||
.toString();
|
||||
}
|
||||
return filterToStringCreator(AddResponseHeaderGatewayFilterFactory.this)
|
||||
.append(config.getName(), config.getValue())
|
||||
.toString();
|
||||
@@ -49,12 +78,51 @@ public class AddResponseHeaderGatewayFilterFactory extends AbstractNameValueGate
|
||||
}
|
||||
|
||||
void addHeader(ServerWebExchange exchange, NameValueConfig config) {
|
||||
final String value = ServerWebExchangeUtils.expand(exchange, config.getValue());
|
||||
HttpHeaders headers = exchange.getResponse().getHeaders();
|
||||
// if response has been commited, no more response headers will bee added.
|
||||
if (!exchange.getResponse().isCommitted()) {
|
||||
headers.add(config.getName(), value);
|
||||
final String value = ServerWebExchangeUtils.expand(exchange, config.getValue());
|
||||
HttpHeaders headers = exchange.getResponse().getHeaders();
|
||||
|
||||
boolean override = true; // default is true
|
||||
if (config instanceof Config) {
|
||||
override = ((Config) config).isOverride();
|
||||
}
|
||||
|
||||
if (override) {
|
||||
headers.add(config.getName(), value);
|
||||
}
|
||||
else {
|
||||
boolean headerIsMissingOrBlank = headers.getOrEmpty(config.getName())
|
||||
.stream()
|
||||
.allMatch(h -> !StringUtils.hasText(h));
|
||||
if (headerIsMissingOrBlank) {
|
||||
headers.add(config.getName(), value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Config extends AbstractNameValueGatewayFilterFactory.NameValueConfig {
|
||||
|
||||
private boolean override = true;
|
||||
|
||||
public boolean isOverride() {
|
||||
return override;
|
||||
}
|
||||
|
||||
public Config setOverride(boolean override) {
|
||||
this.override = override;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringCreator(this).append(NAME_KEY, name)
|
||||
.append(VALUE_KEY, value)
|
||||
.append(OVERRIDE_KEY, override)
|
||||
.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -226,6 +226,22 @@ public class GatewayFilterSpec extends UriSpec {
|
||||
.apply(c -> c.setName(headerName).setValue(headerValue)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a header to the response returned to the Gateway from the route.
|
||||
* @param headerName the header name
|
||||
* @param headerValue the header value
|
||||
* @param override override or not
|
||||
* @return a {@link GatewayFilterSpec} that can be used to apply additional filters
|
||||
*/
|
||||
public GatewayFilterSpec addResponseHeader(String headerName, String headerValue, boolean override) {
|
||||
AddResponseHeaderGatewayFilterFactory.Config config = new AddResponseHeaderGatewayFilterFactory.Config();
|
||||
config.setName(headerName);
|
||||
config.setValue(headerValue);
|
||||
config.setOverride(override);
|
||||
|
||||
return filter(getBean(AddResponseHeaderGatewayFilterFactory.class).apply(config));
|
||||
}
|
||||
|
||||
/**
|
||||
* A filter that adds a local cache for storing response body for repeated requests.
|
||||
* <p>
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
package org.springframework.cloud.gateway.filter.factory;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -51,15 +53,64 @@ class AddResponseHeaderGatewayFilterFactoryTests extends BaseWebClientTests {
|
||||
.header("Host", host)
|
||||
.exchange()
|
||||
.expectHeader()
|
||||
.valueEquals("X-Request-Foo", expectedValue);
|
||||
.valueEquals("X-Request-Foo", expectedValue)
|
||||
.expectHeader()
|
||||
.valueEquals("X-Request-Example", "ValueA");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testResponseHeaderFilterHeaderPresent() {
|
||||
URI uri = UriComponentsBuilder.fromUriString(this.baseUri + "/headers").build(true).toUri();
|
||||
String host = "www.addresponseheader.org";
|
||||
String expectedValue = "Bar";
|
||||
|
||||
Map<String, String> body = new HashMap<>();
|
||||
body.put("X-Request-Example", "ValueB");
|
||||
|
||||
testClient.patch()
|
||||
.uri(uri)
|
||||
.header("Host", host)
|
||||
.bodyValue(body)
|
||||
.exchange()
|
||||
.expectHeader()
|
||||
.valueEquals("X-Request-Foo", expectedValue)
|
||||
.expectHeader()
|
||||
.valueEquals("X-Request-Example", "ValueB");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testResponseHeaderFilterJavaDsl() {
|
||||
URI uri = UriComponentsBuilder.fromUriString(this.baseUri + "/get").build(true).toUri();
|
||||
URI uri = UriComponentsBuilder.fromUriString(this.baseUri + "/headers").build(true).toUri();
|
||||
String host = "www.addresponseheaderjava.org";
|
||||
String expectedValue = "myresponsevalue-www";
|
||||
testClient.get().uri(uri).header("Host", host).exchange().expectHeader().valueEquals("example", expectedValue);
|
||||
testClient.get()
|
||||
.uri(uri)
|
||||
.header("Host", host)
|
||||
.exchange()
|
||||
.expectHeader()
|
||||
.valueEquals("example", expectedValue)
|
||||
.expectHeader()
|
||||
.valueEquals("example2", "myresponsevalue2-www");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testResponseHeaderFilterHeaderPresentJavaDsl() {
|
||||
URI uri = UriComponentsBuilder.fromUriString(this.baseUri + "/headers").build(true).toUri();
|
||||
String host = "www.addresponseheaderjava.org";
|
||||
String expectedValue = "myresponsevalue-www";
|
||||
|
||||
Map<String, String> body = new HashMap<>();
|
||||
body.put("example2", "myresponsevalue2");
|
||||
|
||||
testClient.patch()
|
||||
.uri(uri)
|
||||
.header("Host", host)
|
||||
.bodyValue(body)
|
||||
.exchange()
|
||||
.expectHeader()
|
||||
.valueEquals("example", expectedValue)
|
||||
.expectHeader()
|
||||
.valueEquals("example2", "myresponsevalue2");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -81,11 +132,11 @@ class AddResponseHeaderGatewayFilterFactoryTests extends BaseWebClientTests {
|
||||
public RouteLocator testRouteLocator(RouteLocatorBuilder builder) {
|
||||
return builder.routes()
|
||||
.route("add_response_header_java_test",
|
||||
r -> r.path("/get")
|
||||
r -> r.path("/headers")
|
||||
.and()
|
||||
.host("{sub}.addresponseheaderjava.org")
|
||||
.filters(
|
||||
f -> f.prefixPath("/httpbin").addResponseHeader("example", "myresponsevalue-{sub}"))
|
||||
.filters(f -> f.addResponseHeader("example", "myresponsevalue-{sub}")
|
||||
.addResponseHeader("example2", "myresponsevalue2-{sub}", false))
|
||||
.uri(uri))
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -72,6 +72,7 @@ spring:
|
||||
- Path=/headers
|
||||
filters:
|
||||
- AddResponseHeader=X-Request-Foo, Bar
|
||||
- AddResponseHeader=X-Request-Example, ValueA, false
|
||||
|
||||
- id: cache_request_body_test
|
||||
uri: ${test.uri}
|
||||
|
||||
Reference in New Issue
Block a user