[BAEL-3313] spring-cloud/spring-cloud-gateway | Writing custom Spring Cloud Gateway Filters -- address comments (#8251)
* Addressed comments: * Removed Global filter bean with @Order annotation, now using class that implements Ordered * Added logic to actually mutate the request entity (and the exchange) for the Modify Request example * changed endpoint for languageServiceEndpoint in the chain requests example * removed order from first simple global filter, since well be covering that with other global filter
This commit is contained in:
parent
2b256270fe
commit
0b49d2ad6b
@ -28,14 +28,14 @@ public class ChainRequestGatewayFilterFactory extends AbstractGatewayFilterFacto
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> shortcutFieldOrder() {
|
public List<String> shortcutFieldOrder() {
|
||||||
return Arrays.asList("endpoint", "defaultLanguage");
|
return Arrays.asList("languageServiceEndpoint", "defaultLanguage");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GatewayFilter apply(Config config) {
|
public GatewayFilter apply(Config config) {
|
||||||
return (exchange, chain) -> {
|
return (exchange, chain) -> {
|
||||||
return client.get()
|
return client.get()
|
||||||
.uri(config.getEndpoint())
|
.uri(config.getLanguageServiceEndpoint())
|
||||||
.exchange()
|
.exchange()
|
||||||
.flatMap(response -> {
|
.flatMap(response -> {
|
||||||
return (response.statusCode()
|
return (response.statusCode()
|
||||||
@ -45,8 +45,7 @@ public class ChainRequestGatewayFilterFactory extends AbstractGatewayFilterFacto
|
|||||||
.map(range -> {
|
.map(range -> {
|
||||||
exchange.getRequest()
|
exchange.getRequest()
|
||||||
.mutate()
|
.mutate()
|
||||||
.headers(h -> h.setAcceptLanguage(range))
|
.headers(h -> h.setAcceptLanguage(range));
|
||||||
.build();
|
|
||||||
|
|
||||||
String allOutgoingRequestLanguages = exchange.getRequest()
|
String allOutgoingRequestLanguages = exchange.getRequest()
|
||||||
.getHeaders()
|
.getHeaders()
|
||||||
@ -65,18 +64,18 @@ public class ChainRequestGatewayFilterFactory extends AbstractGatewayFilterFacto
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class Config {
|
public static class Config {
|
||||||
private String endpoint;
|
private String languageServiceEndpoint;
|
||||||
private String defaultLanguage;
|
private String defaultLanguage;
|
||||||
|
|
||||||
public Config() {
|
public Config() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getEndpoint() {
|
public String getLanguageServiceEndpoint() {
|
||||||
return endpoint;
|
return languageServiceEndpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEndpoint(String endpoint) {
|
public void setLanguageServiceEndpoint(String languageServiceEndpoint) {
|
||||||
this.endpoint = endpoint;
|
this.languageServiceEndpoint = languageServiceEndpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDefaultLanguage() {
|
public String getDefaultLanguage() {
|
||||||
|
@ -40,7 +40,7 @@ public class LoggingGatewayFilterFactory extends AbstractGatewayFilterFactory<Lo
|
|||||||
if (config.isPostLogger())
|
if (config.isPostLogger())
|
||||||
logger.info("Post GatewayFilter logging: " + config.getBaseMessage());
|
logger.info("Post GatewayFilter logging: " + config.getBaseMessage());
|
||||||
}));
|
}));
|
||||||
}, -2);
|
}, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Config {
|
public static class Config {
|
||||||
|
@ -12,6 +12,9 @@ import org.slf4j.LoggerFactory;
|
|||||||
import org.springframework.cloud.gateway.filter.GatewayFilter;
|
import org.springframework.cloud.gateway.filter.GatewayFilter;
|
||||||
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
|
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class ModifyRequestGatewayFilterFactory extends AbstractGatewayFilterFactory<ModifyRequestGatewayFilterFactory.Config> {
|
public class ModifyRequestGatewayFilterFactory extends AbstractGatewayFilterFactory<ModifyRequestGatewayFilterFactory.Config> {
|
||||||
@ -45,8 +48,7 @@ public class ModifyRequestGatewayFilterFactory extends AbstractGatewayFilterFact
|
|||||||
|
|
||||||
exchange.getRequest()
|
exchange.getRequest()
|
||||||
.mutate()
|
.mutate()
|
||||||
.headers(h -> h.setAcceptLanguageAsLocales(Collections.singletonList(requestLocale)))
|
.headers(h -> h.setAcceptLanguageAsLocales(Collections.singletonList(requestLocale)));
|
||||||
.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String allOutgoingRequestLanguages = exchange.getRequest()
|
String allOutgoingRequestLanguages = exchange.getRequest()
|
||||||
@ -56,8 +58,20 @@ public class ModifyRequestGatewayFilterFactory extends AbstractGatewayFilterFact
|
|||||||
.map(range -> range.getRange())
|
.map(range -> range.getRange())
|
||||||
.collect(Collectors.joining(","));
|
.collect(Collectors.joining(","));
|
||||||
|
|
||||||
logger.info("Modify Request output - Request contains Accept-Language header: " + allOutgoingRequestLanguages);
|
logger.info("Modify request output - Request contains Accept-Language header: {}", allOutgoingRequestLanguages);
|
||||||
return chain.filter(exchange);
|
|
||||||
|
ServerWebExchange modifiedExchange = exchange.mutate()
|
||||||
|
.request(originalRequest -> originalRequest.uri(UriComponentsBuilder.fromUri(exchange.getRequest()
|
||||||
|
.getURI())
|
||||||
|
.replaceQueryParams(new LinkedMultiValueMap<String, String>())
|
||||||
|
.build()
|
||||||
|
.toUri()))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
logger.info("Removed all query params: {}", modifiedExchange.getRequest()
|
||||||
|
.getURI());
|
||||||
|
|
||||||
|
return chain.filter(modifiedExchange);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
package com.baeldung.springcloudgateway.customfilters.filters.global;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||||
|
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class FirstPreLastPostGlobalFilter implements GlobalFilter, Ordered {
|
||||||
|
|
||||||
|
final Logger logger = LoggerFactory.getLogger(FirstPreLastPostGlobalFilter.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
||||||
|
logger.info("First Pre Global Filter");
|
||||||
|
return chain.filter(exchange)
|
||||||
|
.then(Mono.fromRunnable(() -> {
|
||||||
|
logger.info("Last Post Global Filter");
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOrder() {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,6 @@ import org.slf4j.LoggerFactory;
|
|||||||
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.core.annotation.Order;
|
|
||||||
|
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
@ -23,17 +22,4 @@ public class LoggingGlobalFiltersConfigurations {
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
|
||||||
@Order(-1)
|
|
||||||
public GlobalFilter FirstPreLastPostGlobalFilter() {
|
|
||||||
return (exchange, chain) -> {
|
|
||||||
logger.info("First Pre Global Filter");
|
|
||||||
return chain.filter(exchange)
|
|
||||||
.then(Mono.fromRunnable(() -> {
|
|
||||||
logger.info("Last Post Global Filter");
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,14 +4,13 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||||
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||||
import org.springframework.core.Ordered;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.server.ServerWebExchange;
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class LoggingGlobalPreFilter implements GlobalFilter, Ordered {
|
public class LoggingGlobalPreFilter implements GlobalFilter {
|
||||||
|
|
||||||
final Logger logger = LoggerFactory.getLogger(LoggingGlobalPreFilter.class);
|
final Logger logger = LoggerFactory.getLogger(LoggingGlobalPreFilter.class);
|
||||||
|
|
||||||
@ -20,9 +19,4 @@ public class LoggingGlobalPreFilter implements GlobalFilter, Ordered {
|
|||||||
logger.info("Global Pre Filter executed");
|
logger.info("Global Pre Filter executed");
|
||||||
return chain.filter(exchange);
|
return chain.filter(exchange);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getOrder() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,8 @@ spring.cloud.gateway.routes[0].filters[1]=Logging=My Custom Message, true, true
|
|||||||
#spring.cloud.gateway.routes[0].filters[1].args[preLogger]=true
|
#spring.cloud.gateway.routes[0].filters[1].args[preLogger]=true
|
||||||
#spring.cloud.gateway.routes[0].filters[1].args[postLogger]=true
|
#spring.cloud.gateway.routes[0].filters[1].args[postLogger]=true
|
||||||
|
|
||||||
spring.cloud.gateway.routes[0].filters[2]=ModifyRequest=en
|
spring.cloud.gateway.routes[0].filters[2]=ModifyResponse
|
||||||
spring.cloud.gateway.routes[0].filters[3]=ModifyResponse
|
spring.cloud.gateway.routes[0].filters[3]=ModifyRequest=en
|
||||||
spring.cloud.gateway.routes[0].filters[4]=ChainRequest=http://localhost:8082/resource/language, fr
|
spring.cloud.gateway.routes[0].filters[4]=ChainRequest=http://localhost:8082/resource/language, fr
|
||||||
|
|
||||||
management.endpoints.web.exposure.include=*
|
management.endpoints.web.exposure.include=*
|
||||||
|
@ -45,6 +45,8 @@ public class CustomFiltersLiveTest {
|
|||||||
|
|
||||||
response.expectStatus()
|
response.expectStatus()
|
||||||
.isOk()
|
.isOk()
|
||||||
|
.expectHeader()
|
||||||
|
.doesNotExist("Bael-Custom-Language-Header")
|
||||||
.expectBody(String.class)
|
.expectBody(String.class)
|
||||||
.isEqualTo("Service Resource");
|
.isEqualTo("Service Resource");
|
||||||
|
|
||||||
@ -60,7 +62,8 @@ public class CustomFiltersLiveTest {
|
|||||||
.haveAtLeastOne(eventContains("Pre GatewayFilter logging: My Custom Message"))
|
.haveAtLeastOne(eventContains("Pre GatewayFilter logging: My Custom Message"))
|
||||||
.haveAtLeastOne(eventContains("Post GatewayFilter logging: My Custom Message"))
|
.haveAtLeastOne(eventContains("Post GatewayFilter logging: My Custom Message"))
|
||||||
// Modify Request
|
// Modify Request
|
||||||
.haveAtLeastOne(eventContains("Modify Request output - Request contains Accept-Language header:"))
|
.haveAtLeastOne(eventContains("Modify request output - Request contains Accept-Language header:"))
|
||||||
|
.haveAtLeastOne(eventContainsExcept("Removed all query params: ", "locale"))
|
||||||
// Modify Response
|
// Modify Response
|
||||||
.areNot(eventContains("Added custom header to Response"))
|
.areNot(eventContains("Added custom header to Response"))
|
||||||
// Chain Request
|
// Chain Request
|
||||||
@ -75,16 +78,33 @@ public class CustomFiltersLiveTest {
|
|||||||
|
|
||||||
response.expectStatus()
|
response.expectStatus()
|
||||||
.isOk()
|
.isOk()
|
||||||
|
.expectHeader()
|
||||||
|
.exists("Bael-Custom-Language-Header")
|
||||||
.expectBody(String.class)
|
.expectBody(String.class)
|
||||||
.isEqualTo("Service Resource");
|
.isEqualTo("Service Resource");
|
||||||
|
|
||||||
assertThat(LoggerListAppender.getEvents())
|
assertThat(LoggerListAppender.getEvents())
|
||||||
// Modify Response
|
// Modify Response
|
||||||
.haveAtLeastOne(eventContains("Added custom header to Response"));
|
.haveAtLeastOne(eventContains("Added custom header to Response"))
|
||||||
|
.haveAtLeastOne(eventContainsExcept("Removed all query params: ", "locale"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This condition will be successful if the event contains a substring
|
||||||
|
*/
|
||||||
private Condition<ILoggingEvent> eventContains(String substring) {
|
private Condition<ILoggingEvent> eventContains(String substring) {
|
||||||
return new Condition<ILoggingEvent>(entry -> (substring == null || (entry.getFormattedMessage() != null && entry.getFormattedMessage()
|
return new Condition<ILoggingEvent>(entry -> (substring == null || (entry.getFormattedMessage() != null && entry.getFormattedMessage()
|
||||||
.contains(substring))), String.format("entry with message '%s'", substring));
|
.contains(substring))), String.format("entry with message '%s'", substring));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This condition will be successful if the event contains a substring, but not another one
|
||||||
|
*/
|
||||||
|
private Condition<ILoggingEvent> eventContainsExcept(String substring, String except) {
|
||||||
|
return new Condition<ILoggingEvent>(entry -> (substring == null || (entry.getFormattedMessage() != null && entry.getFormattedMessage()
|
||||||
|
.contains(substring)
|
||||||
|
&& !entry.getFormattedMessage()
|
||||||
|
.contains(except))),
|
||||||
|
String.format("entry with message '%s'", substring));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user