Skip to content

Commit bde4e32

Browse files
committed
Merge branch '4.2.x'
2 parents 2dfc3f3 + 34f38ea commit bde4e32

File tree

5 files changed

+149
-10
lines changed

5 files changed

+149
-10
lines changed

docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/addresponseheader-factory.adoc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[[addresponseheader-gatewayfilter-factory]]
22
= `AddResponseHeader` `GatewayFilter` Factory
33

4-
The `AddResponseHeader` `GatewayFilter` Factory takes a `name` and `value` parameter.
4+
The `AddResponseHeader` `GatewayFilter` Factory takes three parameters: `name`, `value` and `override`(default value is `true`) .
55
The following example configures an `AddResponseHeader` `GatewayFilter`:
66

77
.application.yml
@@ -15,9 +15,12 @@ spring:
1515
uri: https://example.org
1616
filters:
1717
- AddResponseHeader=X-Response-Red, Blue
18+
- AddResponseHeader=X-Response-Black, White, false
1819
----
1920

2021
This adds `X-Response-Red:Blue` header to the downstream response's headers for all matching requests.
22+
and if the response already contains the `X-Response-Black` header, this will not add the `X-Response-Black: White`
23+
header to the downstream response's headers for all matching requests.
2124

2225
`AddResponseHeader` is aware of URI variables used to match a path or host.
2326
URI variables may be used in the value and are expanded at runtime.

spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/AddResponseHeaderGatewayFilterFactory.java

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,17 @@
1616

1717
package org.springframework.cloud.gateway.filter.factory;
1818

19+
import java.util.Arrays;
20+
import java.util.List;
21+
1922
import reactor.core.publisher.Mono;
2023

2124
import org.springframework.cloud.gateway.filter.GatewayFilter;
2225
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
2326
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
27+
import org.springframework.core.style.ToStringCreator;
2428
import org.springframework.http.HttpHeaders;
29+
import org.springframework.util.StringUtils;
2530
import org.springframework.web.server.ServerWebExchange;
2631

2732
import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator;
@@ -31,6 +36,23 @@
3136
*/
3237
public class AddResponseHeaderGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
3338

39+
private static final String OVERRIDE_KEY = "override";
40+
41+
@Override
42+
public Class getConfigClass() {
43+
return Config.class;
44+
}
45+
46+
@Override
47+
public NameValueConfig newConfig() {
48+
return new Config();
49+
}
50+
51+
@Override
52+
public List<String> shortcutFieldOrder() {
53+
return Arrays.asList(GatewayFilter.NAME_KEY, GatewayFilter.VALUE_KEY, OVERRIDE_KEY);
54+
}
55+
3456
@Override
3557
public GatewayFilter apply(NameValueConfig config) {
3658
return new GatewayFilter() {
@@ -41,6 +63,13 @@ public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
4163

4264
@Override
4365
public String toString() {
66+
if (config instanceof Config) {
67+
return filterToStringCreator(AddResponseHeaderGatewayFilterFactory.this)
68+
.append(GatewayFilter.NAME_KEY, config.getName())
69+
.append(GatewayFilter.VALUE_KEY, config.getValue())
70+
.append(OVERRIDE_KEY, ((Config) config).isOverride())
71+
.toString();
72+
}
4473
return filterToStringCreator(AddResponseHeaderGatewayFilterFactory.this)
4574
.append(config.getName(), config.getValue())
4675
.toString();
@@ -49,12 +78,51 @@ public String toString() {
4978
}
5079

5180
void addHeader(ServerWebExchange exchange, NameValueConfig config) {
52-
final String value = ServerWebExchangeUtils.expand(exchange, config.getValue());
53-
HttpHeaders headers = exchange.getResponse().getHeaders();
5481
// if response has been commited, no more response headers will bee added.
5582
if (!exchange.getResponse().isCommitted()) {
56-
headers.add(config.getName(), value);
83+
final String value = ServerWebExchangeUtils.expand(exchange, config.getValue());
84+
HttpHeaders headers = exchange.getResponse().getHeaders();
85+
86+
boolean override = true; // default is true
87+
if (config instanceof Config) {
88+
override = ((Config) config).isOverride();
89+
}
90+
91+
if (override) {
92+
headers.add(config.getName(), value);
93+
}
94+
else {
95+
boolean headerIsMissingOrBlank = headers.getOrEmpty(config.getName())
96+
.stream()
97+
.allMatch(h -> !StringUtils.hasText(h));
98+
if (headerIsMissingOrBlank) {
99+
headers.add(config.getName(), value);
100+
}
101+
}
57102
}
58103
}
59104

105+
public static class Config extends AbstractNameValueGatewayFilterFactory.NameValueConfig {
106+
107+
private boolean override = true;
108+
109+
public boolean isOverride() {
110+
return override;
111+
}
112+
113+
public Config setOverride(boolean override) {
114+
this.override = override;
115+
return this;
116+
}
117+
118+
@Override
119+
public String toString() {
120+
return new ToStringCreator(this).append(NAME_KEY, name)
121+
.append(VALUE_KEY, value)
122+
.append(OVERRIDE_KEY, override)
123+
.toString();
124+
}
125+
126+
}
127+
60128
}

spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,22 @@ public GatewayFilterSpec addResponseHeader(String headerName, String headerValue
226226
.apply(c -> c.setName(headerName).setValue(headerValue)));
227227
}
228228

229+
/**
230+
* Adds a header to the response returned to the Gateway from the route.
231+
* @param headerName the header name
232+
* @param headerValue the header value
233+
* @param override override or not
234+
* @return a {@link GatewayFilterSpec} that can be used to apply additional filters
235+
*/
236+
public GatewayFilterSpec addResponseHeader(String headerName, String headerValue, boolean override) {
237+
AddResponseHeaderGatewayFilterFactory.Config config = new AddResponseHeaderGatewayFilterFactory.Config();
238+
config.setName(headerName);
239+
config.setValue(headerValue);
240+
config.setOverride(override);
241+
242+
return filter(getBean(AddResponseHeaderGatewayFilterFactory.class).apply(config));
243+
}
244+
229245
/**
230246
* A filter that adds a local cache for storing response body for repeated requests.
231247
* <p>

spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/AddResponseHeaderGatewayFilterFactoryTests.java

Lines changed: 57 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
package org.springframework.cloud.gateway.filter.factory;
1818

1919
import java.net.URI;
20+
import java.util.HashMap;
21+
import java.util.Map;
2022

2123
import org.junit.jupiter.api.Test;
2224

@@ -51,15 +53,64 @@ void testResponseHeaderFilter() {
5153
.header("Host", host)
5254
.exchange()
5355
.expectHeader()
54-
.valueEquals("X-Request-Foo", expectedValue);
56+
.valueEquals("X-Request-Foo", expectedValue)
57+
.expectHeader()
58+
.valueEquals("X-Request-Example", "ValueA");
59+
}
60+
61+
@Test
62+
void testResponseHeaderFilterHeaderPresent() {
63+
URI uri = UriComponentsBuilder.fromUriString(this.baseUri + "/headers").build(true).toUri();
64+
String host = "www.addresponseheader.org";
65+
String expectedValue = "Bar";
66+
67+
Map<String, String> body = new HashMap<>();
68+
body.put("X-Request-Example", "ValueB");
69+
70+
testClient.patch()
71+
.uri(uri)
72+
.header("Host", host)
73+
.bodyValue(body)
74+
.exchange()
75+
.expectHeader()
76+
.valueEquals("X-Request-Foo", expectedValue)
77+
.expectHeader()
78+
.valueEquals("X-Request-Example", "ValueB");
5579
}
5680

5781
@Test
5882
void testResponseHeaderFilterJavaDsl() {
59-
URI uri = UriComponentsBuilder.fromUriString(this.baseUri + "/get").build(true).toUri();
83+
URI uri = UriComponentsBuilder.fromUriString(this.baseUri + "/headers").build(true).toUri();
84+
String host = "www.addresponseheaderjava.org";
85+
String expectedValue = "myresponsevalue-www";
86+
testClient.get()
87+
.uri(uri)
88+
.header("Host", host)
89+
.exchange()
90+
.expectHeader()
91+
.valueEquals("example", expectedValue)
92+
.expectHeader()
93+
.valueEquals("example2", "myresponsevalue2-www");
94+
}
95+
96+
@Test
97+
void testResponseHeaderFilterHeaderPresentJavaDsl() {
98+
URI uri = UriComponentsBuilder.fromUriString(this.baseUri + "/headers").build(true).toUri();
6099
String host = "www.addresponseheaderjava.org";
61100
String expectedValue = "myresponsevalue-www";
62-
testClient.get().uri(uri).header("Host", host).exchange().expectHeader().valueEquals("example", expectedValue);
101+
102+
Map<String, String> body = new HashMap<>();
103+
body.put("example2", "myresponsevalue2");
104+
105+
testClient.patch()
106+
.uri(uri)
107+
.header("Host", host)
108+
.bodyValue(body)
109+
.exchange()
110+
.expectHeader()
111+
.valueEquals("example", expectedValue)
112+
.expectHeader()
113+
.valueEquals("example2", "myresponsevalue2");
63114
}
64115

65116
@Test
@@ -81,11 +132,11 @@ static class TestConfig {
81132
public RouteLocator testRouteLocator(RouteLocatorBuilder builder) {
82133
return builder.routes()
83134
.route("add_response_header_java_test",
84-
r -> r.path("/get")
135+
r -> r.path("/headers")
85136
.and()
86137
.host("{sub}.addresponseheaderjava.org")
87-
.filters(
88-
f -> f.prefixPath("/httpbin").addResponseHeader("example", "myresponsevalue-{sub}"))
138+
.filters(f -> f.addResponseHeader("example", "myresponsevalue-{sub}")
139+
.addResponseHeader("example2", "myresponsevalue2-{sub}", false))
89140
.uri(uri))
90141
.build();
91142
}

spring-cloud-gateway-server/src/test/resources/application.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ spring:
7272
- Path=/headers
7373
filters:
7474
- AddResponseHeader=X-Request-Foo, Bar
75+
- AddResponseHeader=X-Request-Example, ValueA, false
7576

7677
- id: cache_request_body_test
7778
uri: ${test.uri}

0 commit comments

Comments
 (0)