[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`
This commit is contained in:
parent
60ce9ba95f
commit
ed6d85a620
@ -65,6 +65,14 @@
|
|||||||
<artifactId>jakarta.validation-api</artifactId>
|
<artifactId>jakarta.validation-api</artifactId>
|
||||||
<version>${jakarta.validation-api.version}</version>
|
<version>${jakarta.validation-api.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-cache</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||||
|
<artifactId>caffeine</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
@ -179,11 +187,12 @@
|
|||||||
</profiles>
|
</profiles>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
<spring-boot.version>3.2.3</spring-boot.version>
|
||||||
<spring-cloud-dependencies.version>2023.0.0</spring-cloud-dependencies.version>
|
<spring-cloud-dependencies.version>2023.0.0</spring-cloud-dependencies.version>
|
||||||
<hibernate-validator.version>8.0.1.Final</hibernate-validator.version>
|
<hibernate-validator.version>8.0.1.Final</hibernate-validator.version>
|
||||||
<redis.version>0.7.2</redis.version>
|
<redis.version>0.7.2</redis.version>
|
||||||
<oauth2-oidc-sdk.version>9.19</oauth2-oidc-sdk.version>
|
<oauth2-oidc-sdk.version>9.19</oauth2-oidc-sdk.version>
|
||||||
<!-- <junit-bom.version>5.5.2</junit-bom.version> -->
|
<junit-jupiter.version>5.10.2</junit-jupiter.version>
|
||||||
<jakarta.validation-api.version>3.0.2</jakarta.validation-api.version>
|
<jakarta.validation-api.version>3.0.2</jakarta.validation-api.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.baeldung.springcloudgateway.webfilters;
|
||||||
|
|
||||||
|
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||||
|
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||||
|
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class CacheEvaluationFilter implements GlobalFilter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
||||||
|
String body = exchange.getAttribute(ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR);
|
||||||
|
if (body != null) {
|
||||||
|
exchange.getResponse().getHeaders().add("My-Header-Cache", body);
|
||||||
|
}
|
||||||
|
return chain.filter(exchange);
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,11 @@ spring:
|
|||||||
port: 6379
|
port: 6379
|
||||||
cloud:
|
cloud:
|
||||||
gateway:
|
gateway:
|
||||||
|
filter:
|
||||||
|
local-response-cache:
|
||||||
|
enabled: true
|
||||||
|
timeToLive: 20m
|
||||||
|
size: 6MB
|
||||||
routes:
|
routes:
|
||||||
- id: request_header_route
|
- id: request_header_route
|
||||||
uri: https://httpbin.org
|
uri: https://httpbin.org
|
||||||
@ -17,6 +22,7 @@ spring:
|
|||||||
filters:
|
filters:
|
||||||
- AddRequestHeader=My-Header-Good,Good
|
- AddRequestHeader=My-Header-Good,Good
|
||||||
- AddRequestHeader=My-Header-Remove,Remove
|
- AddRequestHeader=My-Header-Remove,Remove
|
||||||
|
- AddRequestHeadersIfNotPresent=My-Header-Absent:Absent
|
||||||
- AddRequestParameter=var, good
|
- AddRequestParameter=var, good
|
||||||
- AddRequestParameter=var2, remove
|
- AddRequestParameter=var2, remove
|
||||||
- MapRequestHeader=My-Header-Good, My-Header-Bad
|
- MapRequestHeader=My-Header-Good, My-Header-Bad
|
||||||
@ -31,15 +37,16 @@ spring:
|
|||||||
predicates:
|
predicates:
|
||||||
- Path=/header/post/**
|
- Path=/header/post/**
|
||||||
filters:
|
filters:
|
||||||
- AddResponseHeader=My-Header-Good,Good
|
|
||||||
- AddResponseHeader=My-Header-Set,Good
|
|
||||||
- AddResponseHeader=My-Header-Rewrite, password=12345678
|
|
||||||
- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
|
- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
|
||||||
- AddResponseHeader=My-Header-Remove,Remove
|
|
||||||
- SetResponseHeader=My-Header-Set, Set
|
- SetResponseHeader=My-Header-Set, Set
|
||||||
- RemoveResponseHeader=My-Header-Remove
|
- RemoveResponseHeader=My-Header-Remove
|
||||||
- RewriteResponseHeader=My-Header-Rewrite, password=[^&]+, password=***
|
- RewriteResponseHeader=My-Header-Rewrite, password=[^&]+, password=***
|
||||||
- RewriteLocationResponseHeader=AS_IN_REQUEST, Location, ,
|
- RewriteLocationResponseHeader=AS_IN_REQUEST, Location, ,
|
||||||
|
- RemoveJsonAttributesResponseBody=form,Accept,true
|
||||||
|
- AddResponseHeader=My-Header-Good,Good
|
||||||
|
- AddResponseHeader=My-Header-Set,Good
|
||||||
|
- AddResponseHeader=My-Header-Remove,Remove
|
||||||
|
- AddResponseHeader=My-Header-Rewrite,password=12345678
|
||||||
- StripPrefix=1
|
- StripPrefix=1
|
||||||
|
|
||||||
- id: path_route
|
- id: path_route
|
||||||
@ -89,6 +96,17 @@ spring:
|
|||||||
factor: 2
|
factor: 2
|
||||||
basedOnPreviousValue: false
|
basedOnPreviousValue: false
|
||||||
|
|
||||||
|
- id: circuitbreaker_route
|
||||||
|
uri: https://httpbin.org
|
||||||
|
predicates:
|
||||||
|
- Path=/status/504
|
||||||
|
filters:
|
||||||
|
- name: CircuitBreaker
|
||||||
|
args:
|
||||||
|
name: myCircuitBreaker
|
||||||
|
fallbackUri: forward:/anything
|
||||||
|
- RewritePath=/status/504, /anything
|
||||||
|
|
||||||
- id: request_rate_limiter
|
- id: request_rate_limiter
|
||||||
uri: https://httpbin.org
|
uri: https://httpbin.org
|
||||||
predicates:
|
predicates:
|
||||||
@ -99,4 +117,23 @@ spring:
|
|||||||
args:
|
args:
|
||||||
redis-rate-limiter.replenishRate: 10
|
redis-rate-limiter.replenishRate: 10
|
||||||
redis-rate-limiter.burstCapacity: 5
|
redis-rate-limiter.burstCapacity: 5
|
||||||
|
redis-rate-limiter.requestedTokens: 1
|
||||||
key-resolver: "#{@userKeyResolver}"
|
key-resolver: "#{@userKeyResolver}"
|
||||||
|
|
||||||
|
- id: cache_request_body_route
|
||||||
|
uri: https://httpbin.org
|
||||||
|
predicates:
|
||||||
|
- Path=/cache/post/**
|
||||||
|
filters:
|
||||||
|
- StripPrefix=1
|
||||||
|
- name: CacheRequestBody
|
||||||
|
args:
|
||||||
|
bodyClass: java.lang.String
|
||||||
|
|
||||||
|
- id: cache_response_body_route
|
||||||
|
uri: https://httpbin.org
|
||||||
|
predicates:
|
||||||
|
- Path=/cache/get/**
|
||||||
|
filters:
|
||||||
|
- StripPrefix=1
|
||||||
|
- LocalResponseCache=10s,20MB
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
package com.baeldung.springcloudgateway.webfilters;
|
package com.baeldung.springcloudgateway.webfilters;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import org.assertj.core.api.Condition;
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
@ -23,9 +20,10 @@ import org.springframework.http.ResponseEntity;
|
|||||||
import org.springframework.test.context.ActiveProfiles;
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||||
import org.springframework.test.web.reactive.server.WebTestClient.ResponseSpec;
|
import org.springframework.test.web.reactive.server.WebTestClient.ResponseSpec;
|
||||||
|
import org.springframework.web.reactive.function.BodyInserters;
|
||||||
|
|
||||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||||
@ActiveProfiles("webfilters")
|
@ActiveProfiles({"webfilters","nosecurity"})
|
||||||
public class WebFilterFactoriesLiveTest {
|
public class WebFilterFactoriesLiveTest {
|
||||||
|
|
||||||
@LocalServerPort
|
@LocalServerPort
|
||||||
@ -55,6 +53,7 @@ public class WebFilterFactoriesLiveTest {
|
|||||||
assertThat(headers.getString("My-Header-Good")).isEqualTo("Good");
|
assertThat(headers.getString("My-Header-Good")).isEqualTo("Good");
|
||||||
assertThat(headers.getString("My-Header-Bad")).isEqualTo("Good");
|
assertThat(headers.getString("My-Header-Bad")).isEqualTo("Good");
|
||||||
assertThat(headers.getString("My-Header-Set")).isEqualTo("Set");
|
assertThat(headers.getString("My-Header-Set")).isEqualTo("Set");
|
||||||
|
assertThat(headers.getString("My-Header-Absent")).isEqualTo("Absent");
|
||||||
assertTrue(headers.isNull("My-Header-Remove"));
|
assertTrue(headers.isNull("My-Header-Remove"));
|
||||||
JSONObject vars = json.getJSONObject("args");
|
JSONObject vars = json.getJSONObject("args");
|
||||||
assertThat(vars.getString("var")).isEqualTo("good");
|
assertThat(vars.getString("var")).isEqualTo("good");
|
||||||
@ -75,7 +74,10 @@ public class WebFilterFactoriesLiveTest {
|
|||||||
.expectHeader()
|
.expectHeader()
|
||||||
.valueEquals("My-Header-Good", "Good")
|
.valueEquals("My-Header-Good", "Good")
|
||||||
.expectHeader()
|
.expectHeader()
|
||||||
.doesNotExist("My-Header-Remove");
|
.doesNotExist("My-Header-Remove")
|
||||||
|
.expectBody()
|
||||||
|
.jsonPath("$.headers.Accept").doesNotExist()
|
||||||
|
.jsonPath("form").doesNotExist();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -133,4 +135,28 @@ public class WebFilterFactoriesLiveTest {
|
|||||||
JSONObject json = new JSONObject(response.getBody());
|
JSONObject json = new JSONObject(response.getBody());
|
||||||
assertThat(json.getString("url")).contains("anything");
|
assertThat(json.getString("url")).contains("anything");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenCallCachePostThroughGateway_thenMyHeaderCacheIsSet() {
|
||||||
|
ResponseSpec response = client.post()
|
||||||
|
.uri("/cache/post")
|
||||||
|
.body(BodyInserters.fromValue("CachedBody"))
|
||||||
|
.exchange();
|
||||||
|
|
||||||
|
response.expectStatus()
|
||||||
|
.isOk()
|
||||||
|
.expectHeader()
|
||||||
|
.valueEquals("My-Header-Cache", "CachedBody");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenCallCacheGetThroughGateway_thenCacheControlIsSet() {
|
||||||
|
ResponseSpec response = client.get()
|
||||||
|
.uri("/cache/get")
|
||||||
|
.exchange();
|
||||||
|
|
||||||
|
response.expectStatus().isOk()
|
||||||
|
.expectHeader()
|
||||||
|
.valueEquals("Cache-Control", "max-age=10");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user