Skip to content

Commit ca861ff

Browse files
committed
add new config for AddResponseHeaderGatewayFilterFactory
Signed-off-by: jiangyuan <joe469391363@gmail.com>
1 parent 6fc7ee7 commit ca861ff

File tree

4 files changed

+154
-15
lines changed

4 files changed

+154
-15
lines changed

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

Lines changed: 81 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,40 @@
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;
2833

2934
/**
3035
* @author Spencer Gibb
3136
*/
32-
public class AddResponseHeaderGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
37+
public class AddResponseHeaderGatewayFilterFactory
38+
extends AbstractGatewayFilterFactory<AddResponseHeaderGatewayFilterFactory.Config> {
39+
40+
private static final String OVERRIDE_KEY = "override";
41+
42+
public AddResponseHeaderGatewayFilterFactory() {
43+
super(Config.class);
44+
}
3345

3446
@Override
35-
public GatewayFilter apply(NameValueConfig config) {
47+
public List<String> shortcutFieldOrder() {
48+
return Arrays.asList(GatewayFilter.NAME_KEY, GatewayFilter.VALUE_KEY, OVERRIDE_KEY);
49+
}
50+
51+
@Override
52+
public GatewayFilter apply(Config config) {
3653
return new GatewayFilter() {
3754
@Override
3855
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
@@ -42,19 +59,76 @@ public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
4259
@Override
4360
public String toString() {
4461
return filterToStringCreator(AddResponseHeaderGatewayFilterFactory.this)
45-
.append(config.getName(), config.getValue())
62+
.append(GatewayFilter.NAME_KEY, config.getName())
63+
.append(GatewayFilter.VALUE_KEY, config.getValue())
64+
.append(OVERRIDE_KEY, config.isOverride())
4665
.toString();
4766
}
4867
};
4968
}
5069

51-
void addHeader(ServerWebExchange exchange, NameValueConfig config) {
52-
final String value = ServerWebExchangeUtils.expand(exchange, config.getValue());
53-
HttpHeaders headers = exchange.getResponse().getHeaders();
70+
void addHeader(ServerWebExchange exchange, Config config) {
5471
// if response has been commited, no more response headers will bee added.
5572
if (!exchange.getResponse().isCommitted()) {
56-
headers.add(config.getName(), value);
73+
final String value = ServerWebExchangeUtils.expand(exchange, config.getValue());
74+
HttpHeaders headers = exchange.getResponse().getHeaders();
75+
if (config.override) {
76+
headers.add(config.getName(), value);
77+
}
78+
else {
79+
boolean headerIsMissingOrBlank = headers.getOrEmpty(config.getName())
80+
.stream()
81+
.allMatch(h -> !StringUtils.hasText(h));
82+
if (headerIsMissingOrBlank) {
83+
headers.add(config.getName(), value);
84+
}
85+
}
5786
}
5887
}
5988

89+
public static class Config {
90+
91+
private String name;
92+
93+
private String value;
94+
95+
private boolean override = true;
96+
97+
public String getName() {
98+
return name;
99+
}
100+
101+
public Config setName(String name) {
102+
this.name = name;
103+
return this;
104+
}
105+
106+
public String getValue() {
107+
return value;
108+
}
109+
110+
public Config setValue(String value) {
111+
this.value = value;
112+
return this;
113+
}
114+
115+
public boolean isOverride() {
116+
return override;
117+
}
118+
119+
public Config setOverride(boolean override) {
120+
this.override = override;
121+
return this;
122+
}
123+
124+
@Override
125+
public String toString() {
126+
return new ToStringCreator(this).append(NAME_KEY, name)
127+
.append(VALUE_KEY, value)
128+
.append(OVERRIDE_KEY, override)
129+
.toString();
130+
}
131+
132+
}
133+
60134
}

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

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

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

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

Lines changed: 60 additions & 8 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

@@ -25,7 +27,6 @@
2527
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
2628
import org.springframework.boot.test.context.SpringBootTest;
2729
import org.springframework.cloud.gateway.filter.GatewayFilter;
28-
import org.springframework.cloud.gateway.filter.factory.AbstractNameValueGatewayFilterFactory.NameValueConfig;
2930
import org.springframework.cloud.gateway.route.RouteLocator;
3031
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
3132
import org.springframework.cloud.gateway.test.BaseWebClientTests;
@@ -51,20 +52,71 @@ void testResponseHeaderFilter() {
5152
.header("Host", host)
5253
.exchange()
5354
.expectHeader()
54-
.valueEquals("X-Request-Foo", expectedValue);
55+
.valueEquals("X-Request-Foo", expectedValue)
56+
.expectHeader()
57+
.valueEquals("X-Request-Example", "ValueA");
58+
}
59+
60+
@Test
61+
void testResponseHeaderFilterHeaderPresent() {
62+
URI uri = UriComponentsBuilder.fromUriString(this.baseUri + "/headers").build(true).toUri();
63+
String host = "www.addresponseheader.org";
64+
String expectedValue = "Bar";
65+
66+
Map<String, String> body = new HashMap<>();
67+
body.put("X-Request-Example", "ValueB");
68+
69+
testClient.patch()
70+
.uri(uri)
71+
.header("Host", host)
72+
.bodyValue(body)
73+
.exchange()
74+
.expectHeader()
75+
.valueEquals("X-Request-Foo", expectedValue)
76+
.expectHeader()
77+
.valueEquals("X-Request-Example", "ValueB");
5578
}
5679

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

65115
@Test
66116
void toStringFormat() {
67-
NameValueConfig config = new NameValueConfig().setName("myname").setValue("myvalue");
117+
AddResponseHeaderGatewayFilterFactory.Config config = new AddResponseHeaderGatewayFilterFactory.Config()
118+
.setName("myname")
119+
.setValue("myvalue");
68120
GatewayFilter filter = new AddResponseHeaderGatewayFilterFactory().apply(config);
69121
assertThat(filter.toString()).contains("myname").contains("myvalue");
70122
}
@@ -81,11 +133,11 @@ static class TestConfig {
81133
public RouteLocator testRouteLocator(RouteLocatorBuilder builder) {
82134
return builder.routes()
83135
.route("add_response_header_java_test",
84-
r -> r.path("/get")
136+
r -> r.path("/headers")
85137
.and()
86138
.host("{sub}.addresponseheaderjava.org")
87-
.filters(
88-
f -> f.prefixPath("/httpbin").addResponseHeader("example", "myresponsevalue-{sub}"))
139+
.filters(f -> f.addResponseHeader("example", "myresponsevalue-{sub}")
140+
.addResponseHeader("example2", "myresponsevalue2-{sub}", false))
89141
.uri(uri))
90142
.build();
91143
}

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)