Skip to content

Commit ed6d85a

Browse files
authored
[BAEL-6276] Exploring the New Filters on Spring Cloud Gateway (#16341)
* BAEL-6276: Fix the broken tests * BAEL-6276: Add request header AddRequestHeadersIfNotPresent * BAEL-6276: Add response header RemoveJsonAttributesResponseBody * BAEL-6276: Example for CacheRequestBody * BAEL-6276: Example for LocalResponseCache * BAEL-6276: Add `redis-rate-limiter.requestedTokens` for `RequestRateLimiter`
1 parent 60ce9ba commit ed6d85a

4 files changed

Lines changed: 107 additions & 13 deletions

File tree

spring-cloud-modules/spring-cloud-gateway/pom.xml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,14 @@
6565
<artifactId>jakarta.validation-api</artifactId>
6666
<version>${jakarta.validation-api.version}</version>
6767
</dependency>
68+
<dependency>
69+
<groupId>org.springframework.boot</groupId>
70+
<artifactId>spring-boot-starter-cache</artifactId>
71+
</dependency>
72+
<dependency>
73+
<groupId>com.github.ben-manes.caffeine</groupId>
74+
<artifactId>caffeine</artifactId>
75+
</dependency>
6876
<dependency>
6977
<groupId>org.springframework.boot</groupId>
7078
<artifactId>spring-boot-starter-actuator</artifactId>
@@ -179,11 +187,12 @@
179187
</profiles>
180188

181189
<properties>
190+
<spring-boot.version>3.2.3</spring-boot.version>
182191
<spring-cloud-dependencies.version>2023.0.0</spring-cloud-dependencies.version>
183192
<hibernate-validator.version>8.0.1.Final</hibernate-validator.version>
184193
<redis.version>0.7.2</redis.version>
185194
<oauth2-oidc-sdk.version>9.19</oauth2-oidc-sdk.version>
186-
<!-- <junit-bom.version>5.5.2</junit-bom.version> -->
195+
<junit-jupiter.version>5.10.2</junit-jupiter.version>
187196
<jakarta.validation-api.version>3.0.2</jakarta.validation-api.version>
188197
</properties>
189198

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.baeldung.springcloudgateway.webfilters;
2+
3+
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
4+
import org.springframework.cloud.gateway.filter.GlobalFilter;
5+
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
6+
import org.springframework.stereotype.Component;
7+
import org.springframework.web.server.ServerWebExchange;
8+
9+
import reactor.core.publisher.Mono;
10+
11+
@Component
12+
public class CacheEvaluationFilter implements GlobalFilter {
13+
14+
@Override
15+
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
16+
String body = exchange.getAttribute(ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR);
17+
if (body != null) {
18+
exchange.getResponse().getHeaders().add("My-Header-Cache", body);
19+
}
20+
return chain.filter(exchange);
21+
}
22+
}

spring-cloud-modules/spring-cloud-gateway/src/main/resources/application-webfilters.yml

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ spring:
99
port: 6379
1010
cloud:
1111
gateway:
12+
filter:
13+
local-response-cache:
14+
enabled: true
15+
timeToLive: 20m
16+
size: 6MB
1217
routes:
1318
- id: request_header_route
1419
uri: https://httpbin.org
@@ -17,6 +22,7 @@ spring:
1722
filters:
1823
- AddRequestHeader=My-Header-Good,Good
1924
- AddRequestHeader=My-Header-Remove,Remove
25+
- AddRequestHeadersIfNotPresent=My-Header-Absent:Absent
2026
- AddRequestParameter=var, good
2127
- AddRequestParameter=var2, remove
2228
- MapRequestHeader=My-Header-Good, My-Header-Bad
@@ -31,17 +37,18 @@ spring:
3137
predicates:
3238
- Path=/header/post/**
3339
filters:
34-
- AddResponseHeader=My-Header-Good,Good
35-
- AddResponseHeader=My-Header-Set,Good
36-
- AddResponseHeader=My-Header-Rewrite, password=12345678
3740
- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
38-
- AddResponseHeader=My-Header-Remove,Remove
3941
- SetResponseHeader=My-Header-Set, Set
4042
- RemoveResponseHeader=My-Header-Remove
4143
- RewriteResponseHeader=My-Header-Rewrite, password=[^&]+, password=***
4244
- RewriteLocationResponseHeader=AS_IN_REQUEST, Location, ,
45+
- RemoveJsonAttributesResponseBody=form,Accept,true
46+
- AddResponseHeader=My-Header-Good,Good
47+
- AddResponseHeader=My-Header-Set,Good
48+
- AddResponseHeader=My-Header-Remove,Remove
49+
- AddResponseHeader=My-Header-Rewrite,password=12345678
4350
- StripPrefix=1
44-
51+
4552
- id: path_route
4653
uri: https://httpbin.org
4754
predicates:
@@ -88,7 +95,18 @@ spring:
8895
maxBackoff: 50ms
8996
factor: 2
9097
basedOnPreviousValue: false
91-
98+
99+
- id: circuitbreaker_route
100+
uri: https://httpbin.org
101+
predicates:
102+
- Path=/status/504
103+
filters:
104+
- name: CircuitBreaker
105+
args:
106+
name: myCircuitBreaker
107+
fallbackUri: forward:/anything
108+
- RewritePath=/status/504, /anything
109+
92110
- id: request_rate_limiter
93111
uri: https://httpbin.org
94112
predicates:
@@ -99,4 +117,23 @@ spring:
99117
args:
100118
redis-rate-limiter.replenishRate: 10
101119
redis-rate-limiter.burstCapacity: 5
102-
key-resolver: "#{@userKeyResolver}"
120+
redis-rate-limiter.requestedTokens: 1
121+
key-resolver: "#{@userKeyResolver}"
122+
123+
- id: cache_request_body_route
124+
uri: https://httpbin.org
125+
predicates:
126+
- Path=/cache/post/**
127+
filters:
128+
- StripPrefix=1
129+
- name: CacheRequestBody
130+
args:
131+
bodyClass: java.lang.String
132+
133+
- id: cache_response_body_route
134+
uri: https://httpbin.org
135+
predicates:
136+
- Path=/cache/get/**
137+
filters:
138+
- StripPrefix=1
139+
- LocalResponseCache=10s,20MB

spring-cloud-modules/spring-cloud-gateway/src/test/java/com/baeldung/springcloudgateway/webfilters/WebFilterFactoriesLiveTest.java

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
package com.baeldung.springcloudgateway.webfilters;
22

33
import static org.assertj.core.api.Assertions.assertThat;
4-
import static org.junit.Assert.assertFalse;
5-
import static org.junit.Assert.assertNull;
64
import static org.junit.Assert.assertTrue;
75

8-
import org.assertj.core.api.Condition;
96
import org.json.JSONException;
107
import org.json.JSONObject;
118
import org.junit.jupiter.api.BeforeEach;
@@ -23,9 +20,10 @@
2320
import org.springframework.test.context.ActiveProfiles;
2421
import org.springframework.test.web.reactive.server.WebTestClient;
2522
import org.springframework.test.web.reactive.server.WebTestClient.ResponseSpec;
23+
import org.springframework.web.reactive.function.BodyInserters;
2624

2725
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
28-
@ActiveProfiles("webfilters")
26+
@ActiveProfiles({"webfilters","nosecurity"})
2927
public class WebFilterFactoriesLiveTest {
3028

3129
@LocalServerPort
@@ -55,6 +53,7 @@ public void whenCallGetThroughGateway_thenAllHTTPRequestHeadersParametersAreSet(
5553
assertThat(headers.getString("My-Header-Good")).isEqualTo("Good");
5654
assertThat(headers.getString("My-Header-Bad")).isEqualTo("Good");
5755
assertThat(headers.getString("My-Header-Set")).isEqualTo("Set");
56+
assertThat(headers.getString("My-Header-Absent")).isEqualTo("Absent");
5857
assertTrue(headers.isNull("My-Header-Remove"));
5958
JSONObject vars = json.getJSONObject("args");
6059
assertThat(vars.getString("var")).isEqualTo("good");
@@ -75,7 +74,10 @@ public void whenCallHeaderPostThroughGateway_thenAllHTTPResponseHeadersAreSet()
7574
.expectHeader()
7675
.valueEquals("My-Header-Good", "Good")
7776
.expectHeader()
78-
.doesNotExist("My-Header-Remove");
77+
.doesNotExist("My-Header-Remove")
78+
.expectBody()
79+
.jsonPath("$.headers.Accept").doesNotExist()
80+
.jsonPath("form").doesNotExist();
7981
}
8082

8183
@Test
@@ -133,4 +135,28 @@ public void whenCallStatus504ThroughGateway_thenCircuitBreakerIsExecuted() throw
133135
JSONObject json = new JSONObject(response.getBody());
134136
assertThat(json.getString("url")).contains("anything");
135137
}
138+
139+
@Test
140+
public void whenCallCachePostThroughGateway_thenMyHeaderCacheIsSet() {
141+
ResponseSpec response = client.post()
142+
.uri("/cache/post")
143+
.body(BodyInserters.fromValue("CachedBody"))
144+
.exchange();
145+
146+
response.expectStatus()
147+
.isOk()
148+
.expectHeader()
149+
.valueEquals("My-Header-Cache", "CachedBody");
150+
}
151+
152+
@Test
153+
public void whenCallCacheGetThroughGateway_thenCacheControlIsSet() {
154+
ResponseSpec response = client.get()
155+
.uri("/cache/get")
156+
.exchange();
157+
158+
response.expectStatus().isOk()
159+
.expectHeader()
160+
.valueEquals("Cache-Control", "max-age=10");
161+
}
136162
}

0 commit comments

Comments
 (0)