JAVA-13321 New Gateway-2 module with spring-cloud-gateway article's subjects
This commit is contained in:
		
							parent
							
								
									f1b3f233dc
								
							
						
					
					
						commit
						a06a2415db
					
				| @ -5,9 +5,3 @@ This module contains articles about Spring Cloud Gateway | |||||||
| ### Relevant Articles: | ### Relevant Articles: | ||||||
| 
 | 
 | ||||||
| - [Exploring the New Spring Cloud Gateway](http://www.baeldung.com/spring-cloud-gateway) | - [Exploring the New Spring Cloud Gateway](http://www.baeldung.com/spring-cloud-gateway) | ||||||
| - [Writing Custom Spring Cloud Gateway Filters](https://www.baeldung.com/spring-cloud-custom-gateway-filters) |  | ||||||
| - [Spring Cloud Gateway Routing Predicate Factories](https://www.baeldung.com/spring-cloud-gateway-routing-predicate-factories) |  | ||||||
| - [Spring Cloud Gateway WebFilter Factories](https://www.baeldung.com/spring-cloud-gateway-webfilter-factories) |  | ||||||
| - [Using Spring Cloud Gateway with OAuth 2.0 Patterns](https://www.baeldung.com/spring-cloud-gateway-oauth2) |  | ||||||
| - [URL Rewriting With Spring Cloud Gateway](https://www.baeldung.com/spring-cloud-gateway-url-rewriting) |  | ||||||
| - [Processing the Response Body in Spring Cloud Gateway](https://www.baeldung.com/spring-cloud-gateway-response-body) |  | ||||||
|  | |||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -4,13 +4,14 @@ | |||||||
|     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||||
|     <modelVersion>4.0.0</modelVersion> |     <modelVersion>4.0.0</modelVersion> | ||||||
|     <artifactId>gateway-2</artifactId> |     <artifactId>gateway-2</artifactId> | ||||||
|     <name>spring-cloud-gateway</name> |     <name>gateway-2</name> | ||||||
|     <packaging>jar</packaging> |     <packaging>jar</packaging> | ||||||
| 
 | 
 | ||||||
|     <parent> |     <parent> | ||||||
|         <groupId>com.baeldung.spring.cloud</groupId> |         <groupId>com.baeldung</groupId> | ||||||
|         <artifactId>spring-cloud-modules</artifactId> |         <artifactId>parent-boot-2</artifactId> | ||||||
|         <version>1.0.0-SNAPSHOT</version> |         <version>0.0.1-SNAPSHOT</version> | ||||||
|  |         <relativePath>../../../parent-boot-2</relativePath> | ||||||
|     </parent> |     </parent> | ||||||
| 
 | 
 | ||||||
|     <dependencyManagement> |     <dependencyManagement> | ||||||
| @ -44,107 +45,36 @@ | |||||||
|             <groupId>org.springframework.cloud</groupId> |             <groupId>org.springframework.cloud</groupId> | ||||||
|             <artifactId>spring-cloud-starter-gateway</artifactId> |             <artifactId>spring-cloud-starter-gateway</artifactId> | ||||||
|         </dependency> |         </dependency> | ||||||
|         <!-- Circuit Breaker --> |  | ||||||
|         <dependency> |  | ||||||
|             <groupId>org.springframework.cloud</groupId> |  | ||||||
|             <artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId> |  | ||||||
|         </dependency> |  | ||||||
|         <!-- Redis --> |  | ||||||
|         <dependency> |  | ||||||
|             <groupId>org.springframework.boot</groupId> |  | ||||||
|             <artifactId>spring-boot-starter-data-redis-reactive</artifactId> |  | ||||||
|         </dependency> |  | ||||||
|         <!-- Embedded Redis --> |  | ||||||
|         <dependency> |  | ||||||
|             <groupId>it.ozimov</groupId> |  | ||||||
|             <artifactId>embedded-redis</artifactId> |  | ||||||
|             <version>${redis.version}</version> |  | ||||||
|             <scope>test</scope> |  | ||||||
|         </dependency> |  | ||||||
|         <dependency> |  | ||||||
|             <groupId>org.hibernate</groupId> |  | ||||||
|             <artifactId>hibernate-validator-cdi</artifactId> |  | ||||||
|             <version>${hibernate-validator.version}</version> |  | ||||||
|         </dependency> |  | ||||||
|         <dependency> |  | ||||||
|             <groupId>javax.validation</groupId> |  | ||||||
|             <artifactId>validation-api</artifactId> |  | ||||||
|         </dependency> |  | ||||||
|         <dependency> |  | ||||||
|             <groupId>org.springframework.boot</groupId> |  | ||||||
|             <artifactId>spring-boot-starter-actuator</artifactId> |  | ||||||
|         </dependency> |  | ||||||
|         <dependency> |  | ||||||
|             <groupId>org.springframework.boot</groupId> |  | ||||||
|             <artifactId>spring-boot-starter-test</artifactId> |  | ||||||
|             <scope>test</scope> |  | ||||||
|         </dependency> |  | ||||||
|         <dependency> |  | ||||||
|             <groupId>org.springframework.boot</groupId> |  | ||||||
|             <artifactId>spring-boot-devtools</artifactId> |  | ||||||
|         </dependency> |  | ||||||
|         <!-- Spring security --> |  | ||||||
|         <dependency> |  | ||||||
|             <groupId>org.springframework.boot</groupId> |  | ||||||
|             <artifactId>spring-boot-starter-oauth2-resource-server</artifactId> |  | ||||||
|         </dependency> |  | ||||||
|         <dependency> |  | ||||||
|             <groupId>org.springframework.boot</groupId> |  | ||||||
|             <artifactId>spring-boot-starter-oauth2-client</artifactId> |  | ||||||
|         </dependency> |  | ||||||
|     </dependencies> |     </dependencies> | ||||||
| 
 | 
 | ||||||
|     <build> | <!--    <build>--> | ||||||
|         <plugins> | <!--        <plugins>--> | ||||||
|             <plugin> | <!--            <plugin>--> | ||||||
|                 <groupId>org.apache.maven.plugins</groupId> | <!--                <groupId>org.apache.maven.plugins</groupId>--> | ||||||
|                 <artifactId>maven-compiler-plugin</artifactId> | <!--                <artifactId>maven-compiler-plugin</artifactId>--> | ||||||
|                 <version>3.8.1</version> | <!--                <version>3.8.1</version>--> | ||||||
|                 <configuration> | <!--                <configuration>--> | ||||||
|                     <source>${java.version}</source> | <!--                    <source>${java.version}</source>--> | ||||||
|                     <target>${java.version}</target> | <!--                    <target>${java.version}</target>--> | ||||||
|                 </configuration> | <!--                </configuration>--> | ||||||
|             </plugin> | <!--            </plugin>--> | ||||||
|             <plugin> | <!--            <plugin>--> | ||||||
|                 <groupId>org.springframework.boot</groupId> | <!--                <groupId>org.springframework.boot</groupId>--> | ||||||
|                 <artifactId>spring-boot-maven-plugin</artifactId> | <!--                <artifactId>spring-boot-maven-plugin</artifactId>--> | ||||||
|                 <configuration> | <!--                <configuration>--> | ||||||
|                     <excludes> | <!--                    <excludes>--> | ||||||
|                         <exclude> | <!--                        <exclude>--> | ||||||
|                             <groupId>org.projectlombok</groupId> | <!--                            <groupId>org.projectlombok</groupId>--> | ||||||
|                             <artifactId>lombok</artifactId> | <!--                            <artifactId>lombok</artifactId>--> | ||||||
|                         </exclude> | <!--                        </exclude>--> | ||||||
|                     </excludes> | <!--                    </excludes>--> | ||||||
|                 </configuration> | <!--                </configuration>--> | ||||||
|             </plugin> | <!--            </plugin>--> | ||||||
|         </plugins> | <!--        </plugins>--> | ||||||
|     </build> | <!--    </build>--> | ||||||
| 
 |  | ||||||
|     <profiles> |  | ||||||
|         <profile> |  | ||||||
|             <id>gateway-url-rewrite</id> |  | ||||||
|             <build> |  | ||||||
|                 <plugins> |  | ||||||
|                     <plugin> |  | ||||||
|                         <groupId>org.springframework.boot</groupId> |  | ||||||
|                         <artifactId>spring-boot-maven-plugin</artifactId> |  | ||||||
|                         <configuration> |  | ||||||
|                             <mainClass>com.baeldung.springcloudgateway.rewrite.URLRewriteGatewayApplication</mainClass> |  | ||||||
|                             <jvmArguments>-Dspring.profiles.active=url-rewrite</jvmArguments> |  | ||||||
|                         </configuration> |  | ||||||
|                     </plugin> |  | ||||||
|                 </plugins> |  | ||||||
|             </build> |  | ||||||
|         </profile> |  | ||||||
|     </profiles> |  | ||||||
| 
 | 
 | ||||||
|     <properties> |     <properties> | ||||||
|         <!-- <spring-cloud-dependencies.version>Hoxton.SR3</spring-cloud-dependencies.version> --> |         <spring-cloud-dependencies.version>2021.0.3</spring-cloud-dependencies.version> | ||||||
|         <!-- <spring-boot.version>2.2.6.RELEASE</spring-boot.version> --> |  | ||||||
|         <hibernate-validator.version>6.0.2.Final</hibernate-validator.version> |  | ||||||
|         <redis.version>0.7.2</redis.version> |  | ||||||
|         <oauth2-oidc-sdk.version>9.19</oauth2-oidc-sdk.version> |  | ||||||
|         <!-- <junit-bom.version>5.5.2</junit-bom.version> --> |  | ||||||
|     </properties> |     </properties> | ||||||
| 
 | 
 | ||||||
| </project> | </project> | ||||||
| @ -1,15 +0,0 @@ | |||||||
| package com.baeldung.springcloudgateway.customfilters.gatewayapp; |  | ||||||
| 
 |  | ||||||
| import org.springframework.boot.SpringApplication; |  | ||||||
| import org.springframework.boot.autoconfigure.SpringBootApplication; |  | ||||||
| import org.springframework.context.annotation.PropertySource; |  | ||||||
| 
 |  | ||||||
| @SpringBootApplication |  | ||||||
| @PropertySource("classpath:customfilters-global-application.properties") |  | ||||||
| public class CustomFiltersGatewayApplication { |  | ||||||
| 
 |  | ||||||
|     public static void main(String[] args) { |  | ||||||
|         SpringApplication.run(CustomFiltersGatewayApplication.class, args); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| @ -1,16 +0,0 @@ | |||||||
| package com.baeldung.springcloudgateway.customfilters.gatewayapp.config; |  | ||||||
| 
 |  | ||||||
| import org.springframework.context.annotation.Bean; |  | ||||||
| import org.springframework.context.annotation.Configuration; |  | ||||||
| import org.springframework.web.reactive.function.client.WebClient; |  | ||||||
| 
 |  | ||||||
| @Configuration |  | ||||||
| public class WebClientConfig { |  | ||||||
| 
 |  | ||||||
|     @Bean |  | ||||||
|     WebClient client() { |  | ||||||
|         return WebClient.builder() |  | ||||||
|             .build(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| @ -1,89 +0,0 @@ | |||||||
| package com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories; |  | ||||||
| 
 |  | ||||||
| import java.util.Arrays; |  | ||||||
| import java.util.List; |  | ||||||
| import java.util.Locale.LanguageRange; |  | ||||||
| import java.util.stream.Collectors; |  | ||||||
| 
 |  | ||||||
| import org.slf4j.Logger; |  | ||||||
| import org.slf4j.LoggerFactory; |  | ||||||
| import org.springframework.cloud.gateway.filter.GatewayFilter; |  | ||||||
| import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; |  | ||||||
| import org.springframework.stereotype.Component; |  | ||||||
| import org.springframework.web.reactive.function.client.WebClient; |  | ||||||
| 
 |  | ||||||
| import reactor.core.publisher.Mono; |  | ||||||
| 
 |  | ||||||
| @Component |  | ||||||
| public class ChainRequestGatewayFilterFactory extends AbstractGatewayFilterFactory<ChainRequestGatewayFilterFactory.Config> { |  | ||||||
| 
 |  | ||||||
|     final Logger logger = LoggerFactory.getLogger(ChainRequestGatewayFilterFactory.class); |  | ||||||
| 
 |  | ||||||
|     private final WebClient client; |  | ||||||
| 
 |  | ||||||
|     public ChainRequestGatewayFilterFactory(WebClient client) { |  | ||||||
|         super(Config.class); |  | ||||||
|         this.client = client; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public List<String> shortcutFieldOrder() { |  | ||||||
|         return Arrays.asList("languageServiceEndpoint", "defaultLanguage"); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public GatewayFilter apply(Config config) { |  | ||||||
|         return (exchange, chain) -> { |  | ||||||
|             return client.get() |  | ||||||
|                 .uri(config.getLanguageServiceEndpoint()) |  | ||||||
|                 .exchange() |  | ||||||
|                 .flatMap(response -> { |  | ||||||
|                     return (response.statusCode() |  | ||||||
|                         .is2xxSuccessful()) ? response.bodyToMono(String.class) : Mono.just(config.getDefaultLanguage()); |  | ||||||
|                 }) |  | ||||||
|                 .map(LanguageRange::parse) |  | ||||||
|                 .map(range -> { |  | ||||||
|                     exchange.getRequest() |  | ||||||
|                         .mutate() |  | ||||||
|                         .headers(h -> h.setAcceptLanguage(range)); |  | ||||||
| 
 |  | ||||||
|                     String allOutgoingRequestLanguages = exchange.getRequest() |  | ||||||
|                         .getHeaders() |  | ||||||
|                         .getAcceptLanguage() |  | ||||||
|                         .stream() |  | ||||||
|                         .map(r -> r.getRange()) |  | ||||||
|                         .collect(Collectors.joining(",")); |  | ||||||
| 
 |  | ||||||
|                     logger.info("Chain Request output - Request contains Accept-Language header: " + allOutgoingRequestLanguages); |  | ||||||
| 
 |  | ||||||
|                     return exchange; |  | ||||||
|                 }) |  | ||||||
|                 .flatMap(chain::filter); |  | ||||||
| 
 |  | ||||||
|         }; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public static class Config { |  | ||||||
|         private String languageServiceEndpoint; |  | ||||||
|         private String defaultLanguage; |  | ||||||
| 
 |  | ||||||
|         public Config() { |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public String getLanguageServiceEndpoint() { |  | ||||||
|             return languageServiceEndpoint; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public void setLanguageServiceEndpoint(String languageServiceEndpoint) { |  | ||||||
|             this.languageServiceEndpoint = languageServiceEndpoint; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public String getDefaultLanguage() { |  | ||||||
|             return defaultLanguage; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public void setDefaultLanguage(String defaultLanguage) { |  | ||||||
|             this.defaultLanguage = defaultLanguage; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,85 +0,0 @@ | |||||||
| package com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories; |  | ||||||
| 
 |  | ||||||
| import java.util.Arrays; |  | ||||||
| import java.util.List; |  | ||||||
| 
 |  | ||||||
| import org.slf4j.Logger; |  | ||||||
| import org.slf4j.LoggerFactory; |  | ||||||
| import org.springframework.cloud.gateway.filter.GatewayFilter; |  | ||||||
| import org.springframework.cloud.gateway.filter.OrderedGatewayFilter; |  | ||||||
| import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; |  | ||||||
| import org.springframework.stereotype.Component; |  | ||||||
| 
 |  | ||||||
| import reactor.core.publisher.Mono; |  | ||||||
| 
 |  | ||||||
| @Component |  | ||||||
| public class LoggingGatewayFilterFactory extends AbstractGatewayFilterFactory<LoggingGatewayFilterFactory.Config> { |  | ||||||
| 
 |  | ||||||
|     final Logger logger = LoggerFactory.getLogger(LoggingGatewayFilterFactory.class); |  | ||||||
| 
 |  | ||||||
|     public static final String BASE_MSG = "baseMessage"; |  | ||||||
|     public static final String PRE_LOGGER = "preLogger"; |  | ||||||
|     public static final String POST_LOGGER = "postLogger"; |  | ||||||
| 
 |  | ||||||
|     public LoggingGatewayFilterFactory() { |  | ||||||
|         super(Config.class); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public List<String> shortcutFieldOrder() { |  | ||||||
|         return Arrays.asList(BASE_MSG, PRE_LOGGER, POST_LOGGER); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public GatewayFilter apply(Config config) { |  | ||||||
|         return new OrderedGatewayFilter((exchange, chain) -> { |  | ||||||
|             if (config.isPreLogger()) |  | ||||||
|                 logger.info("Pre GatewayFilter logging: " + config.getBaseMessage()); |  | ||||||
|             return chain.filter(exchange) |  | ||||||
|                 .then(Mono.fromRunnable(() -> { |  | ||||||
|                     if (config.isPostLogger()) |  | ||||||
|                         logger.info("Post GatewayFilter logging: " + config.getBaseMessage()); |  | ||||||
|                 })); |  | ||||||
|         }, 1); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public static class Config { |  | ||||||
|         private String baseMessage; |  | ||||||
|         private boolean preLogger; |  | ||||||
|         private boolean postLogger; |  | ||||||
| 
 |  | ||||||
|         public Config() { |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
|         public Config(String baseMessage, boolean preLogger, boolean postLogger) { |  | ||||||
|             super(); |  | ||||||
|             this.baseMessage = baseMessage; |  | ||||||
|             this.preLogger = preLogger; |  | ||||||
|             this.postLogger = postLogger; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public String getBaseMessage() { |  | ||||||
|             return this.baseMessage; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public boolean isPreLogger() { |  | ||||||
|             return preLogger; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public boolean isPostLogger() { |  | ||||||
|             return postLogger; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public void setBaseMessage(String baseMessage) { |  | ||||||
|             this.baseMessage = baseMessage; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public void setPreLogger(boolean preLogger) { |  | ||||||
|             this.preLogger = preLogger; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public void setPostLogger(boolean postLogger) { |  | ||||||
|             this.postLogger = postLogger; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,92 +0,0 @@ | |||||||
| package com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories; |  | ||||||
| 
 |  | ||||||
| import java.util.Arrays; |  | ||||||
| import java.util.Collections; |  | ||||||
| import java.util.List; |  | ||||||
| import java.util.Locale; |  | ||||||
| import java.util.Optional; |  | ||||||
| import java.util.stream.Collectors; |  | ||||||
| 
 |  | ||||||
| import org.slf4j.Logger; |  | ||||||
| import org.slf4j.LoggerFactory; |  | ||||||
| import org.springframework.cloud.gateway.filter.GatewayFilter; |  | ||||||
| import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; |  | ||||||
| import org.springframework.stereotype.Component; |  | ||||||
| import org.springframework.util.LinkedMultiValueMap; |  | ||||||
| import org.springframework.web.server.ServerWebExchange; |  | ||||||
| import org.springframework.web.util.UriComponentsBuilder; |  | ||||||
| 
 |  | ||||||
| @Component |  | ||||||
| public class ModifyRequestGatewayFilterFactory extends AbstractGatewayFilterFactory<ModifyRequestGatewayFilterFactory.Config> { |  | ||||||
| 
 |  | ||||||
|     final Logger logger = LoggerFactory.getLogger(ModifyRequestGatewayFilterFactory.class); |  | ||||||
| 
 |  | ||||||
|     public ModifyRequestGatewayFilterFactory() { |  | ||||||
|         super(Config.class); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public List<String> shortcutFieldOrder() { |  | ||||||
|         return Arrays.asList("defaultLocale"); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public GatewayFilter apply(Config config) { |  | ||||||
|         return (exchange, chain) -> { |  | ||||||
|             if (exchange.getRequest() |  | ||||||
|                 .getHeaders() |  | ||||||
|                 .getAcceptLanguage() |  | ||||||
|                 .isEmpty()) { |  | ||||||
| 
 |  | ||||||
|                 String queryParamLocale = exchange.getRequest() |  | ||||||
|                     .getQueryParams() |  | ||||||
|                     .getFirst("locale"); |  | ||||||
| 
 |  | ||||||
|                 Locale requestLocale = Optional.ofNullable(queryParamLocale) |  | ||||||
|                     .map(l -> Locale.forLanguageTag(l)) |  | ||||||
|                     .orElse(config.getDefaultLocale()); |  | ||||||
| 
 |  | ||||||
|                 exchange.getRequest() |  | ||||||
|                     .mutate() |  | ||||||
|                     .headers(h -> h.setAcceptLanguageAsLocales(Collections.singletonList(requestLocale))); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             String allOutgoingRequestLanguages = exchange.getRequest() |  | ||||||
|                 .getHeaders() |  | ||||||
|                 .getAcceptLanguage() |  | ||||||
|                 .stream() |  | ||||||
|                 .map(range -> range.getRange()) |  | ||||||
|                 .collect(Collectors.joining(",")); |  | ||||||
| 
 |  | ||||||
|             logger.info("Modify request output - Request contains Accept-Language header: {}", allOutgoingRequestLanguages); |  | ||||||
| 
 |  | ||||||
|             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); |  | ||||||
|         }; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public static class Config { |  | ||||||
|         private Locale defaultLocale; |  | ||||||
| 
 |  | ||||||
|         public Config() { |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public Locale getDefaultLocale() { |  | ||||||
|             return defaultLocale; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public void setDefaultLocale(String defaultLocale) { |  | ||||||
|             this.defaultLocale = Locale.forLanguageTag(defaultLocale); |  | ||||||
|         }; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,48 +0,0 @@ | |||||||
| package com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories; |  | ||||||
| 
 |  | ||||||
| import java.util.Optional; |  | ||||||
| 
 |  | ||||||
| import org.slf4j.Logger; |  | ||||||
| import org.slf4j.LoggerFactory; |  | ||||||
| import org.springframework.cloud.gateway.filter.GatewayFilter; |  | ||||||
| import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; |  | ||||||
| import org.springframework.http.server.reactive.ServerHttpResponse; |  | ||||||
| import org.springframework.stereotype.Component; |  | ||||||
| 
 |  | ||||||
| import reactor.core.publisher.Mono; |  | ||||||
| 
 |  | ||||||
| @Component |  | ||||||
| public class ModifyResponseGatewayFilterFactory extends AbstractGatewayFilterFactory<ModifyResponseGatewayFilterFactory.Config> { |  | ||||||
| 
 |  | ||||||
|     final Logger logger = LoggerFactory.getLogger(ModifyResponseGatewayFilterFactory.class); |  | ||||||
| 
 |  | ||||||
|     public ModifyResponseGatewayFilterFactory() { |  | ||||||
|         super(Config.class); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public GatewayFilter apply(Config config) { |  | ||||||
|         return (exchange, chain) -> { |  | ||||||
|             return chain.filter(exchange) |  | ||||||
|                 .then(Mono.fromRunnable(() -> { |  | ||||||
|                     ServerHttpResponse response = exchange.getResponse(); |  | ||||||
| 
 |  | ||||||
|                     Optional.ofNullable(exchange.getRequest() |  | ||||||
|                         .getQueryParams() |  | ||||||
|                         .getFirst("locale")) |  | ||||||
|                         .ifPresent(qp -> { |  | ||||||
|                             String responseContentLanguage = response.getHeaders() |  | ||||||
|                                 .getContentLanguage() |  | ||||||
|                                 .getLanguage(); |  | ||||||
| 
 |  | ||||||
|                             response.getHeaders() |  | ||||||
|                                 .add("Bael-Custom-Language-Header", responseContentLanguage); |  | ||||||
|                             logger.info("Added custom header to Response"); |  | ||||||
|                         }); |  | ||||||
|                 })); |  | ||||||
|         }; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public static class Config { |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,110 +0,0 @@ | |||||||
| package com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories; |  | ||||||
| 
 |  | ||||||
| import java.util.Arrays; |  | ||||||
| import java.util.List; |  | ||||||
| import java.util.regex.Pattern; |  | ||||||
| 
 |  | ||||||
| import org.reactivestreams.Publisher; |  | ||||||
| import org.slf4j.Logger; |  | ||||||
| import org.slf4j.LoggerFactory; |  | ||||||
| import org.springframework.cloud.gateway.filter.GatewayFilter; |  | ||||||
| import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; |  | ||||||
| import org.springframework.cloud.gateway.filter.factory.rewrite.ModifyResponseBodyGatewayFilterFactory; |  | ||||||
| import org.springframework.cloud.gateway.filter.factory.rewrite.RewriteFunction; |  | ||||||
| import org.springframework.stereotype.Component; |  | ||||||
| import org.springframework.web.server.ServerWebExchange; |  | ||||||
| 
 |  | ||||||
| import com.fasterxml.jackson.core.TreeNode; |  | ||||||
| import com.fasterxml.jackson.databind.JsonNode; |  | ||||||
| import com.fasterxml.jackson.databind.node.ArrayNode; |  | ||||||
| import com.fasterxml.jackson.databind.node.ObjectNode; |  | ||||||
| import com.fasterxml.jackson.databind.node.TextNode; |  | ||||||
| 
 |  | ||||||
| import reactor.core.publisher.Mono; |  | ||||||
| 
 |  | ||||||
| @Component |  | ||||||
| public class ScrubResponseGatewayFilterFactory extends AbstractGatewayFilterFactory<ScrubResponseGatewayFilterFactory.Config> { |  | ||||||
| 
 |  | ||||||
|     final Logger logger = LoggerFactory.getLogger(ScrubResponseGatewayFilterFactory.class); |  | ||||||
|     private ModifyResponseBodyGatewayFilterFactory modifyResponseBodyFilterFactory; |  | ||||||
| 
 |  | ||||||
|     public ScrubResponseGatewayFilterFactory(ModifyResponseBodyGatewayFilterFactory modifyResponseBodyFilterFactory) { |  | ||||||
|         super(Config.class); |  | ||||||
|         this.modifyResponseBodyFilterFactory = modifyResponseBodyFilterFactory; |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     @Override |  | ||||||
|     public List<String> shortcutFieldOrder() { |  | ||||||
|         return Arrays.asList("fields", "replacement"); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public GatewayFilter apply(Config config) { |  | ||||||
|          |  | ||||||
|         return modifyResponseBodyFilterFactory |  | ||||||
|           .apply(c -> c.setRewriteFunction(JsonNode.class, JsonNode.class, new Scrubber(config))); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public static class Config { |  | ||||||
|          |  | ||||||
|         private String fields; |  | ||||||
|         private String replacement; |  | ||||||
|          |  | ||||||
|          |  | ||||||
|         public String getFields() { |  | ||||||
|             return fields; |  | ||||||
|         } |  | ||||||
|         public void setFields(String fields) { |  | ||||||
|             this.fields = fields; |  | ||||||
|         } |  | ||||||
|         public String getReplacement() { |  | ||||||
|             return replacement; |  | ||||||
|         } |  | ||||||
|         public void setReplacement(String replacement) { |  | ||||||
|             this.replacement = replacement; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|      |  | ||||||
|     public static class Scrubber implements RewriteFunction<JsonNode,JsonNode> { |  | ||||||
|         private final Pattern fields; |  | ||||||
|         private final String replacement; |  | ||||||
|          |  | ||||||
|         public Scrubber(Config config) { |  | ||||||
|             this.fields = Pattern.compile(config.getFields()); |  | ||||||
|             this.replacement = config.getReplacement(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         @Override |  | ||||||
|         public Publisher<JsonNode> apply(ServerWebExchange t, JsonNode u) { |  | ||||||
|             return Mono.just(scrubRecursively(u)); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         private JsonNode scrubRecursively(JsonNode u) { |  | ||||||
|             if ( !u.isContainerNode()) { |  | ||||||
|                 return u; |  | ||||||
|             } |  | ||||||
|              |  | ||||||
|             if ( u.isObject()) { |  | ||||||
|                 ObjectNode node = (ObjectNode)u; |  | ||||||
|                 node.fields().forEachRemaining((f) -> { |  | ||||||
|                     if ( fields.matcher(f.getKey()).matches() && f.getValue().isTextual()) { |  | ||||||
|                         f.setValue(TextNode.valueOf(replacement)); |  | ||||||
|                     } |  | ||||||
|                     else { |  | ||||||
|                         f.setValue(scrubRecursively(f.getValue())); |  | ||||||
|                     } |  | ||||||
|                 }); |  | ||||||
|             } |  | ||||||
|             else if ( u.isArray()) { |  | ||||||
|                 ArrayNode array = (ArrayNode)u; |  | ||||||
|                 for ( int i = 0 ; i < array.size() ; i++ ) { |  | ||||||
|                     array.set(i, scrubRecursively(array.get(i))); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|              |  | ||||||
|             return u; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,31 +0,0 @@ | |||||||
| package com.baeldung.springcloudgateway.customfilters.gatewayapp.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; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,47 +0,0 @@ | |||||||
| package com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.global; |  | ||||||
| 
 |  | ||||||
| import org.springframework.boot.context.properties.ConfigurationProperties; |  | ||||||
| 
 |  | ||||||
| @ConfigurationProperties("logging.global") |  | ||||||
| public class LoggingGlobalFilterProperties { |  | ||||||
|      |  | ||||||
|     private boolean enabled; |  | ||||||
|     private boolean requestHeaders; |  | ||||||
|     private boolean requestBody; |  | ||||||
|     private boolean responseHeaders; |  | ||||||
|     private boolean responseBody; |  | ||||||
|      |  | ||||||
|     public boolean isEnabled() { |  | ||||||
|         return enabled; |  | ||||||
|     } |  | ||||||
|     public void setEnabled(boolean enabled) { |  | ||||||
|         this.enabled = enabled; |  | ||||||
|     } |  | ||||||
|     public boolean isRequestHeaders() { |  | ||||||
|         return requestHeaders; |  | ||||||
|     } |  | ||||||
|     public void setRequestHeaders(boolean requestHeaders) { |  | ||||||
|         this.requestHeaders = requestHeaders; |  | ||||||
|     } |  | ||||||
|     public boolean isRequestBody() { |  | ||||||
|         return requestBody; |  | ||||||
|     } |  | ||||||
|     public void setRequestBody(boolean requestBody) { |  | ||||||
|         this.requestBody = requestBody; |  | ||||||
|     } |  | ||||||
|     public boolean isResponseHeaders() { |  | ||||||
|         return responseHeaders; |  | ||||||
|     } |  | ||||||
|     public void setResponseHeaders(boolean responseHeaders) { |  | ||||||
|         this.responseHeaders = responseHeaders; |  | ||||||
|     } |  | ||||||
|     public boolean isResponseBody() { |  | ||||||
|         return responseBody; |  | ||||||
|     } |  | ||||||
|     public void setResponseBody(boolean responseBody) { |  | ||||||
|         this.responseBody = responseBody; |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|      |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| @ -1,25 +0,0 @@ | |||||||
| package com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.global; |  | ||||||
| 
 |  | ||||||
| import org.slf4j.Logger; |  | ||||||
| import org.slf4j.LoggerFactory; |  | ||||||
| import org.springframework.cloud.gateway.filter.GlobalFilter; |  | ||||||
| import org.springframework.context.annotation.Bean; |  | ||||||
| import org.springframework.context.annotation.Configuration; |  | ||||||
| 
 |  | ||||||
| import reactor.core.publisher.Mono; |  | ||||||
| 
 |  | ||||||
| @Configuration |  | ||||||
| public class LoggingGlobalFiltersConfigurations { |  | ||||||
| 
 |  | ||||||
|     final Logger logger = LoggerFactory.getLogger(LoggingGlobalFiltersConfigurations.class); |  | ||||||
| 
 |  | ||||||
|     @Bean |  | ||||||
|     public GlobalFilter postGlobalFilter() { |  | ||||||
|         return (exchange, chain) -> { |  | ||||||
|             return chain.filter(exchange) |  | ||||||
|                 .then(Mono.fromRunnable(() -> { |  | ||||||
|                     logger.info("Global Post Filter executed"); |  | ||||||
|                 })); |  | ||||||
|         }; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,22 +0,0 @@ | |||||||
| package com.baeldung.springcloudgateway.customfilters.gatewayapp.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.stereotype.Component; |  | ||||||
| import org.springframework.web.server.ServerWebExchange; |  | ||||||
| 
 |  | ||||||
| import reactor.core.publisher.Mono; |  | ||||||
| 
 |  | ||||||
| @Component |  | ||||||
| public class LoggingGlobalPreFilter implements GlobalFilter { |  | ||||||
| 
 |  | ||||||
|     final Logger logger = LoggerFactory.getLogger(LoggingGlobalPreFilter.class); |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { |  | ||||||
|         logger.info("Global Pre Filter executed"); |  | ||||||
|         return chain.filter(exchange); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,28 +0,0 @@ | |||||||
| package com.baeldung.springcloudgateway.customfilters.gatewayapp.routes; |  | ||||||
| 
 |  | ||||||
| import org.springframework.cloud.gateway.route.RouteLocator; |  | ||||||
| import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; |  | ||||||
| import org.springframework.context.annotation.Bean; |  | ||||||
| 
 |  | ||||||
| import com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories.LoggingGatewayFilterFactory; |  | ||||||
| import com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories.LoggingGatewayFilterFactory.Config; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Note: We want to keep this as an example of configuring a Route with a custom filter |  | ||||||
|  * |  | ||||||
|  * This corresponds with the properties configuration we have |  | ||||||
|  */ |  | ||||||
| // @Configuration |  | ||||||
| public class ServiceRouteConfiguration { |  | ||||||
| 
 |  | ||||||
|     @Bean |  | ||||||
|     public RouteLocator routes(RouteLocatorBuilder builder, LoggingGatewayFilterFactory loggingFactory) { |  | ||||||
| 
 |  | ||||||
|         return builder.routes() |  | ||||||
|             .route("service_route_java_config", r -> r.path("/service/**") |  | ||||||
|                 .filters(f -> f.rewritePath("/service(?<segment>/?.*)", "$\\{segment}") |  | ||||||
|                     .filter(loggingFactory.apply(new Config("My Custom Message", true, true)))) |  | ||||||
|                 .uri("http://localhost:8081")) |  | ||||||
|             .build(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,15 +0,0 @@ | |||||||
| package com.baeldung.springcloudgateway.customfilters.secondservice; |  | ||||||
| 
 |  | ||||||
| import org.springframework.boot.SpringApplication; |  | ||||||
| import org.springframework.boot.autoconfigure.SpringBootApplication; |  | ||||||
| import org.springframework.context.annotation.PropertySource; |  | ||||||
| 
 |  | ||||||
| @SpringBootApplication |  | ||||||
| @PropertySource("classpath:secondservice-application.properties") |  | ||||||
| public class SecondServiceApplication { |  | ||||||
| 
 |  | ||||||
|     public static void main(String[] args) { |  | ||||||
|         SpringApplication.run(SecondServiceApplication.class, args); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| @ -1,18 +0,0 @@ | |||||||
| package com.baeldung.springcloudgateway.customfilters.secondservice.web; |  | ||||||
| 
 |  | ||||||
| import org.springframework.http.ResponseEntity; |  | ||||||
| import org.springframework.web.bind.annotation.GetMapping; |  | ||||||
| import org.springframework.web.bind.annotation.RestController; |  | ||||||
| 
 |  | ||||||
| import reactor.core.publisher.Mono; |  | ||||||
| 
 |  | ||||||
| @RestController |  | ||||||
| public class SecondServiceRestController { |  | ||||||
| 
 |  | ||||||
|     @GetMapping("/resource/language") |  | ||||||
|     public Mono<ResponseEntity<String>> getResource() { |  | ||||||
|         return Mono.just(ResponseEntity.ok() |  | ||||||
|             .body("es")); |  | ||||||
| 
 |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,15 +0,0 @@ | |||||||
| package com.baeldung.springcloudgateway.customfilters.service; |  | ||||||
| 
 |  | ||||||
| import org.springframework.boot.SpringApplication; |  | ||||||
| import org.springframework.boot.autoconfigure.SpringBootApplication; |  | ||||||
| import org.springframework.context.annotation.PropertySource; |  | ||||||
| 
 |  | ||||||
| @SpringBootApplication |  | ||||||
| @PropertySource("classpath:service-application.properties") |  | ||||||
| public class ServiceApplication { |  | ||||||
| 
 |  | ||||||
|     public static void main(String[] args) { |  | ||||||
|         SpringApplication.run(ServiceApplication.class, args); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| @ -1,22 +0,0 @@ | |||||||
| package com.baeldung.springcloudgateway.customfilters.service.web; |  | ||||||
| 
 |  | ||||||
| import java.util.Locale; |  | ||||||
| 
 |  | ||||||
| import org.springframework.http.HttpHeaders; |  | ||||||
| import org.springframework.http.ResponseEntity; |  | ||||||
| import org.springframework.web.bind.annotation.GetMapping; |  | ||||||
| import org.springframework.web.bind.annotation.RestController; |  | ||||||
| 
 |  | ||||||
| import reactor.core.publisher.Mono; |  | ||||||
| 
 |  | ||||||
| @RestController |  | ||||||
| public class ServiceRestController { |  | ||||||
| 
 |  | ||||||
|     @GetMapping("/resource") |  | ||||||
|     public Mono<ResponseEntity<String>> getResource() { |  | ||||||
|         return Mono.just(ResponseEntity.ok() |  | ||||||
|             .header(HttpHeaders.CONTENT_LANGUAGE, Locale.ENGLISH.getLanguage()) |  | ||||||
|             .body("Service Resource")); |  | ||||||
| 
 |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,25 +0,0 @@ | |||||||
| /** |  | ||||||
|  *  |  | ||||||
|  */ |  | ||||||
| package com.baeldung.springcloudgateway.rewrite; |  | ||||||
| 
 |  | ||||||
| import org.springframework.boot.autoconfigure.SpringBootApplication; |  | ||||||
| import org.springframework.boot.builder.SpringApplicationBuilder; |  | ||||||
| import org.springframework.cloud.gateway.filter.GatewayFilter; |  | ||||||
| 
 |  | ||||||
| import reactor.core.publisher.Mono; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * @author Baeldung |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
| @SpringBootApplication |  | ||||||
| public class URLRewriteGatewayApplication { |  | ||||||
|      |  | ||||||
|     public static void main(String[] args) { |  | ||||||
|         new SpringApplicationBuilder(URLRewriteGatewayApplication.class) |  | ||||||
|           .profiles("url-rewrite") |  | ||||||
|           .run(args); |  | ||||||
|     } |  | ||||||
|      |  | ||||||
| } |  | ||||||
| @ -1,43 +0,0 @@ | |||||||
| package com.baeldung.springcloudgateway.rewrite.routes; |  | ||||||
| 
 |  | ||||||
| import org.springframework.beans.factory.annotation.Value; |  | ||||||
| import org.springframework.cloud.gateway.route.RouteLocator; |  | ||||||
| import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; |  | ||||||
| import org.springframework.context.annotation.Bean; |  | ||||||
| import org.springframework.context.annotation.Configuration; |  | ||||||
| import org.springframework.context.annotation.Profile; |  | ||||||
| import org.springframework.http.server.reactive.ServerHttpRequest; |  | ||||||
| 
 |  | ||||||
| import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR; |  | ||||||
| import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.addOriginalRequestUrl; |  | ||||||
| 
 |  | ||||||
| import java.util.Random; |  | ||||||
| 
 |  | ||||||
| @Configuration |  | ||||||
| @Profile("url-rewrite") |  | ||||||
| public class DynamicRewriteRoute { |  | ||||||
|      |  | ||||||
|     @Value("${rewrite.backend.uri}") |  | ||||||
|     private String backendUri; |  | ||||||
|     private static Random rnd = new Random(); |  | ||||||
|      |  | ||||||
|     @Bean |  | ||||||
|     public RouteLocator dynamicZipCodeRoute(RouteLocatorBuilder builder) { |  | ||||||
|         return builder.routes() |  | ||||||
|           .route("dynamicRewrite", r -> |  | ||||||
|              r.path("/v2/zip/**") |  | ||||||
|               .filters(f -> f.filter((exchange, chain) -> { |  | ||||||
|                   ServerHttpRequest req = exchange.getRequest(); |  | ||||||
|                   addOriginalRequestUrl(exchange, req.getURI()); |  | ||||||
|                   String path = req.getURI().getRawPath(); |  | ||||||
|                   String newPath = path.replaceAll( |  | ||||||
|                     "/v2/zip/(?<zipcode>.*)",  |  | ||||||
|                     "/api/zip/${zipcode}-" + String.format("%03d", rnd.nextInt(1000))); |  | ||||||
|                   ServerHttpRequest request = req.mutate().path(newPath).build(); |  | ||||||
|                   exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, request.getURI()); |  | ||||||
|                   return chain.filter(exchange.mutate().request(request).build()); |  | ||||||
|               })) |  | ||||||
|               .uri(backendUri)) |  | ||||||
|           .build(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,15 +0,0 @@ | |||||||
| package com.baeldung.springcloudgateway.webfilters; |  | ||||||
| 
 |  | ||||||
| import org.springframework.boot.autoconfigure.SpringBootApplication; |  | ||||||
| import org.springframework.boot.builder.SpringApplicationBuilder; |  | ||||||
| 
 |  | ||||||
| @SpringBootApplication |  | ||||||
| public class WebFilterGatewayApplication { |  | ||||||
| 
 |  | ||||||
|     public static void main(String[] args) { |  | ||||||
|         new SpringApplicationBuilder(WebFilterGatewayApplication.class) |  | ||||||
|           .profiles("url-rewrite") |  | ||||||
|           .run(args); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| @ -1,49 +0,0 @@ | |||||||
| package com.baeldung.springcloudgateway.webfilters.config; |  | ||||||
| 
 |  | ||||||
| import org.springframework.cloud.gateway.route.RouteLocator; |  | ||||||
| import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; |  | ||||||
| import org.springframework.context.annotation.Bean; |  | ||||||
| import org.springframework.context.annotation.Configuration; |  | ||||||
| import org.springframework.http.MediaType; |  | ||||||
| 
 |  | ||||||
| import reactor.core.publisher.Mono; |  | ||||||
| 
 |  | ||||||
| @Configuration |  | ||||||
| public class ModifyBodyRouteConfig { |  | ||||||
| 
 |  | ||||||
|     @Bean |  | ||||||
|     public RouteLocator routes(RouteLocatorBuilder builder) { |  | ||||||
|         return builder.routes() |  | ||||||
|           .route("modify_request_body", r -> r.path("/post") |  | ||||||
|             .filters(f -> f.modifyRequestBody(String.class, Hello.class, MediaType.APPLICATION_JSON_VALUE, |  | ||||||
|               (exchange, s) -> Mono.just(new Hello(s.toUpperCase())))).uri("https://httpbin.org")) |  | ||||||
|           .build(); |  | ||||||
|     }   |  | ||||||
| 
 |  | ||||||
|     @Bean |  | ||||||
|     public RouteLocator responseRoutes(RouteLocatorBuilder builder) { |  | ||||||
|         return builder.routes() |  | ||||||
|           .route("modify_response_body", r -> r.path("/put/**") |  | ||||||
|             .filters(f -> f.modifyResponseBody(String.class, Hello.class, MediaType.APPLICATION_JSON_VALUE, |  | ||||||
|               (exchange, s) -> Mono.just(new Hello("New Body")))).uri("https://httpbin.org")) |  | ||||||
|           .build(); |  | ||||||
|     }  |  | ||||||
| 
 |  | ||||||
|     static class Hello { |  | ||||||
|         String message; |  | ||||||
| 
 |  | ||||||
|         public Hello() { } |  | ||||||
| 
 |  | ||||||
|         public Hello(String message) { |  | ||||||
|             this.message = message; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public String getMessage() { |  | ||||||
|             return message; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public void setMessage(String message) { |  | ||||||
|             this.message = message; |  | ||||||
|         } |  | ||||||
|     }  |  | ||||||
| } |  | ||||||
| @ -1,16 +0,0 @@ | |||||||
| package com.baeldung.springcloudgateway.webfilters.config; |  | ||||||
| 
 |  | ||||||
| import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver; |  | ||||||
| import org.springframework.context.annotation.Bean; |  | ||||||
| import org.springframework.context.annotation.Configuration; |  | ||||||
| 
 |  | ||||||
| import reactor.core.publisher.Mono; |  | ||||||
| 
 |  | ||||||
| @Configuration |  | ||||||
| public class RequestRateLimiterResolverConfig { |  | ||||||
|      |  | ||||||
|     @Bean |  | ||||||
|     KeyResolver userKeyResolver() { |  | ||||||
|         return exchange -> Mono.just("1"); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,8 +0,0 @@ | |||||||
| # Enable this profile to disable security |  | ||||||
| spring: |  | ||||||
|   autoconfigure: |  | ||||||
|     exclude: |  | ||||||
|      - org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration |  | ||||||
|      - org.springframework.boot.actuate.autoconfigure.ManagementSecurityAutoConfiguration |  | ||||||
|      - org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration |  | ||||||
|      - org.springframework.boot.actuate.autoconfigure.security.reactive.ReactiveManagementWebSecurityAutoConfiguration |  | ||||||
| @ -1,12 +0,0 @@ | |||||||
| spring: |  | ||||||
|   cloud: |  | ||||||
|     gateway: |  | ||||||
|       routes: |  | ||||||
|       - id: rewrite_with_scrub |  | ||||||
|         uri: ${rewrite.backend.uri:http://example.com} |  | ||||||
|         predicates: |  | ||||||
|         - Path=/v1/customer/** |  | ||||||
|         filters: |  | ||||||
|         - RewritePath=/v1/customer/(?<segment>.*),/api/$\{segment} |  | ||||||
|         - ScrubResponse=ssn,*** |  | ||||||
|          |  | ||||||
| @ -1,11 +0,0 @@ | |||||||
| spring: |  | ||||||
|   cloud: |  | ||||||
|     gateway: |  | ||||||
|       routes: |  | ||||||
|       - id: rewrite_v1 |  | ||||||
|         uri: ${rewrite.backend.uri:http://example.com} |  | ||||||
|         predicates: |  | ||||||
|         - Path=/v1/customer/** |  | ||||||
|         filters: |  | ||||||
|         - RewritePath=/v1/customer/(?<segment>.*),/api/$\{segment} |  | ||||||
|          |  | ||||||
| @ -1,102 +0,0 @@ | |||||||
| logging: |  | ||||||
|   level: |  | ||||||
|     org.springframework.cloud.gateway: INFO |  | ||||||
|     reactor.netty.http.client: INFO |  | ||||||
|      |  | ||||||
| spring: |  | ||||||
|   redis: |  | ||||||
|     host: localhost |  | ||||||
|     port: 6379 |  | ||||||
|   cloud: |  | ||||||
|     gateway: |  | ||||||
|       routes: |  | ||||||
|       - id: request_header_route |  | ||||||
|         uri: https://httpbin.org |  | ||||||
|         predicates: |  | ||||||
|         - Path=/get/** |  | ||||||
|         filters: |  | ||||||
|         - AddRequestHeader=My-Header-Good,Good |  | ||||||
|         - AddRequestHeader=My-Header-Remove,Remove |  | ||||||
|         - AddRequestParameter=var, good |  | ||||||
|         - AddRequestParameter=var2, remove |  | ||||||
|         - MapRequestHeader=My-Header-Good, My-Header-Bad |  | ||||||
|         - MapRequestHeader=My-Header-Set, My-Header-Bad |  | ||||||
|         - SetRequestHeader=My-Header-Set, Set  |  | ||||||
|         - RemoveRequestHeader=My-Header-Remove |  | ||||||
|         - RemoveRequestParameter=var2 |  | ||||||
|         - PreserveHostHeader |  | ||||||
|          |  | ||||||
|       - id: response_header_route |  | ||||||
|         uri: https://httpbin.org |  | ||||||
|         predicates: |  | ||||||
|         - Path=/header/post/** |  | ||||||
|         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 |  | ||||||
|         - AddResponseHeader=My-Header-Remove,Remove |  | ||||||
|         - SetResponseHeader=My-Header-Set, Set |  | ||||||
|         - RemoveResponseHeader=My-Header-Remove |  | ||||||
|         - RewriteResponseHeader=My-Header-Rewrite, password=[^&]+, password=*** |  | ||||||
|         - RewriteLocationResponseHeader=AS_IN_REQUEST, Location, , |  | ||||||
|         - StripPrefix=1 |  | ||||||
|          |  | ||||||
|       - id: path_route |  | ||||||
|         uri: https://httpbin.org |  | ||||||
|         predicates: |  | ||||||
|         - Path=/new/post/** |  | ||||||
|         filters: |  | ||||||
|         - RewritePath=/new(?<segment>/?.*), $\{segment} |  | ||||||
|         - SetPath=/post |  | ||||||
|          |  | ||||||
|       - id: redirect_route |  | ||||||
|         uri: https://httpbin.org |  | ||||||
|         predicates: |  | ||||||
|         - Path=/fake/post/** |  | ||||||
|         filters: |  | ||||||
|         - RedirectTo=302, https://httpbin.org |  | ||||||
|          |  | ||||||
|       - id: status_route |  | ||||||
|         uri: https://httpbin.org |  | ||||||
|         predicates: |  | ||||||
|         - Path=/delete/** |  | ||||||
|         filters: |  | ||||||
|         - SetStatus=401 |  | ||||||
|          |  | ||||||
|       - id: size_route |  | ||||||
|         uri: https://httpbin.org |  | ||||||
|         predicates: |  | ||||||
|         - Path=/anything |  | ||||||
|         filters: |  | ||||||
|         - name: RequestSize |  | ||||||
|           args: |  | ||||||
|             maxSize: 5000000 |  | ||||||
|   |  | ||||||
|       - id: retry_test |  | ||||||
|         uri: https://httpbin.org |  | ||||||
|         predicates: |  | ||||||
|         - Path=/status/502 |  | ||||||
|         filters: |  | ||||||
|         - name: Retry |  | ||||||
|           args: |  | ||||||
|             retries: 3 |  | ||||||
|             statuses: BAD_GATEWAY |  | ||||||
|             methods: GET,POST |  | ||||||
|             backoff: |  | ||||||
|               firstBackoff: 10ms |  | ||||||
|               maxBackoff: 50ms |  | ||||||
|               factor: 2 |  | ||||||
|               basedOnPreviousValue: false |  | ||||||
|                |  | ||||||
|       - id: request_rate_limiter |  | ||||||
|         uri: https://httpbin.org |  | ||||||
|         predicates: |  | ||||||
|         - Path=/redis/get/** |  | ||||||
|         filters: |  | ||||||
|         - StripPrefix=1 |  | ||||||
|         - name: RequestRateLimiter |  | ||||||
|           args: |  | ||||||
|             redis-rate-limiter.replenishRate: 10 |  | ||||||
|             redis-rate-limiter.burstCapacity: 5 |  | ||||||
|             key-resolver: "#{@userKeyResolver}" |  | ||||||
| @ -1,19 +0,0 @@ | |||||||
| spring.cloud.gateway.routes[0].id=service_route |  | ||||||
| spring.cloud.gateway.routes[0].uri=http://localhost:8081 |  | ||||||
| spring.cloud.gateway.routes[0].predicates[0]=Path=/service/** |  | ||||||
| spring.cloud.gateway.routes[0].filters[0]=RewritePath=/service(?<segment>/?.*), $\{segment} |  | ||||||
| spring.cloud.gateway.routes[0].filters[1]=Logging=My Custom Message, true, true |  | ||||||
| # Or, as an alternative: |  | ||||||
| #spring.cloud.gateway.routes[0].filters[1].name=Logging |  | ||||||
| #spring.cloud.gateway.routes[0].filters[1].args[baseMessage]=My Custom Message |  | ||||||
| #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[2]=ModifyResponse |  | ||||||
| spring.cloud.gateway.routes[0].filters[3]=ModifyRequest=en |  | ||||||
| spring.cloud.gateway.routes[0].filters[4]=ChainRequest=http://localhost:8082/resource/language, fr |  | ||||||
| 
 |  | ||||||
| management.endpoints.web.exposure.include=* |  | ||||||
| 
 |  | ||||||
| server.port=80 |  | ||||||
| 
 |  | ||||||
| @ -1 +0,0 @@ | |||||||
| server.port=8082 |  | ||||||
| @ -1 +0,0 @@ | |||||||
| server.port=8081 |  | ||||||
| @ -1,112 +0,0 @@ | |||||||
| package com.baeldung.springcloudgateway.customfilters.gatewayapp; |  | ||||||
| 
 |  | ||||||
| import static org.assertj.core.api.Assertions.assertThat; |  | ||||||
| 
 |  | ||||||
| import org.assertj.core.api.Condition; |  | ||||||
| import org.junit.jupiter.api.BeforeEach; |  | ||||||
| import org.junit.jupiter.api.Test; |  | ||||||
| import org.springframework.beans.factory.annotation.Autowired; |  | ||||||
| import org.springframework.boot.test.context.SpringBootTest; |  | ||||||
| import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; |  | ||||||
| import org.springframework.boot.web.server.LocalServerPort; |  | ||||||
| import org.springframework.test.web.reactive.server.WebTestClient; |  | ||||||
| import org.springframework.test.web.reactive.server.WebTestClient.ResponseSpec; |  | ||||||
| 
 |  | ||||||
| import com.baeldung.springcloudgateway.customfilters.gatewayapp.utils.LoggerListAppender; |  | ||||||
| 
 |  | ||||||
| import ch.qos.logback.classic.spi.ILoggingEvent; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * This test requires: |  | ||||||
|  * * the service in com.baeldung.service running |  | ||||||
|  * * the 'second service' in com.baeldung.secondservice running |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
| @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) |  | ||||||
| public class CustomFiltersLiveTest { |  | ||||||
| 
 |  | ||||||
|     @LocalServerPort |  | ||||||
|     String port; |  | ||||||
| 
 |  | ||||||
|     @Autowired |  | ||||||
|     private WebTestClient client; |  | ||||||
| 
 |  | ||||||
|     @BeforeEach |  | ||||||
|     public void clearLogList() { |  | ||||||
|         LoggerListAppender.clearEventList(); |  | ||||||
|         client = WebTestClient.bindToServer() |  | ||||||
|             .baseUrl("http://localhost:" + port) |  | ||||||
|             .build(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Test |  | ||||||
|     public void whenCallServiceThroughGateway_thenAllConfiguredFiltersGetExecuted() { |  | ||||||
|         ResponseSpec response = client.get() |  | ||||||
|             .uri("/service/resource") |  | ||||||
|             .exchange(); |  | ||||||
| 
 |  | ||||||
|         response.expectStatus() |  | ||||||
|             .isOk() |  | ||||||
|             .expectHeader() |  | ||||||
|             .doesNotExist("Bael-Custom-Language-Header") |  | ||||||
|             .expectBody(String.class) |  | ||||||
|             .isEqualTo("Service Resource"); |  | ||||||
| 
 |  | ||||||
|         assertThat(LoggerListAppender.getEvents()) |  | ||||||
|             // Global Pre Filter |  | ||||||
|             .haveAtLeastOne(eventContains("Global Pre Filter executed")) |  | ||||||
|             // Global Post Filter |  | ||||||
|             .haveAtLeastOne(eventContains("Global Post Filter executed")) |  | ||||||
|             // Global Pre and Post Filter |  | ||||||
|             .haveAtLeastOne(eventContains("First Pre Global Filter")) |  | ||||||
|             .haveAtLeastOne(eventContains("Last Post Global Filter")) |  | ||||||
|             // Logging Filter Factory |  | ||||||
|             .haveAtLeastOne(eventContains("Pre GatewayFilter logging: My Custom Message")) |  | ||||||
|             .haveAtLeastOne(eventContains("Post GatewayFilter logging: My Custom Message")) |  | ||||||
|             // Modify Request |  | ||||||
|             .haveAtLeastOne(eventContains("Modify request output - Request contains Accept-Language header:")) |  | ||||||
|             .haveAtLeastOne(eventContainsExcept("Removed all query params: ", "locale")) |  | ||||||
|             // Modify Response |  | ||||||
|             .areNot(eventContains("Added custom header to Response")) |  | ||||||
|             // Chain Request |  | ||||||
|             .haveAtLeastOne(eventContains("Chain Request output - Request contains Accept-Language header:")); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Test |  | ||||||
|     public void givenRequestWithLocaleQueryParam_whenCallServiceThroughGateway_thenAllConfiguredFiltersGetExecuted() { |  | ||||||
|         ResponseSpec response = client.get() |  | ||||||
|             .uri("/service/resource?locale=en") |  | ||||||
|             .exchange(); |  | ||||||
| 
 |  | ||||||
|         response.expectStatus() |  | ||||||
|             .isOk() |  | ||||||
|             .expectHeader() |  | ||||||
|             .exists("Bael-Custom-Language-Header") |  | ||||||
|             .expectBody(String.class) |  | ||||||
|             .isEqualTo("Service Resource"); |  | ||||||
| 
 |  | ||||||
|         assertThat(LoggerListAppender.getEvents()) |  | ||||||
|             // Modify 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) { |  | ||||||
|         return new Condition<ILoggingEvent>(entry -> (substring == null || (entry.getFormattedMessage() != null && entry.getFormattedMessage() |  | ||||||
|             .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)); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,61 +0,0 @@ | |||||||
| package com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories; |  | ||||||
| 
 |  | ||||||
| import static org.junit.jupiter.api.Assertions.*; |  | ||||||
| 
 |  | ||||||
| import org.junit.jupiter.api.Test; |  | ||||||
| 
 |  | ||||||
| import com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories.ScrubResponseGatewayFilterFactory.Config; |  | ||||||
| import com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories.ScrubResponseGatewayFilterFactory.Scrubber; |  | ||||||
| import com.fasterxml.jackson.core.JsonFactory; |  | ||||||
| import com.fasterxml.jackson.core.JsonParser; |  | ||||||
| import com.fasterxml.jackson.core.ObjectCodec; |  | ||||||
| import com.fasterxml.jackson.core.TreeNode; |  | ||||||
| import com.fasterxml.jackson.databind.JsonNode; |  | ||||||
| import com.fasterxml.jackson.databind.ObjectMapper; |  | ||||||
| 
 |  | ||||||
| import reactor.core.publisher.Mono; |  | ||||||
| 
 |  | ||||||
| class ScrubResponseGatewayFilterFactoryUnitTest { |  | ||||||
|      |  | ||||||
|     private static final String JSON_WITH_FIELDS_TO_SCRUB = "{\r\n" |  | ||||||
|         + "  \"name\" : \"John Doe\",\r\n" |  | ||||||
|         + "        \"ssn\"  : \"123-45-9999\",\r\n" |  | ||||||
|         + "        \"account\" : \"9999888877770000\"\r\n" |  | ||||||
|         + "}"; |  | ||||||
| 
 |  | ||||||
|      |  | ||||||
|     @Test |  | ||||||
|     void givenJsonWithFieldsToScrub_whenApply_thenScrubFields() throws Exception{ |  | ||||||
|          |  | ||||||
|         JsonFactory jf = new JsonFactory(new ObjectMapper()); |  | ||||||
|         JsonParser parser = jf.createParser(JSON_WITH_FIELDS_TO_SCRUB); |  | ||||||
|         JsonNode root = parser.readValueAsTree(); |  | ||||||
|          |  | ||||||
|         Config config = new Config(); |  | ||||||
|         config.setFields("ssn|account"); |  | ||||||
|         config.setReplacement("*"); |  | ||||||
|         Scrubber scrubber = new ScrubResponseGatewayFilterFactory.Scrubber(config); |  | ||||||
|          |  | ||||||
|         JsonNode scrubbed = Mono.from(scrubber.apply(null, root)).block(); |  | ||||||
|         assertNotNull(scrubbed); |  | ||||||
|         assertEquals("*", scrubbed.get("ssn").asText()); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Test |  | ||||||
|     void givenJsonWithoutFieldsToScrub_whenApply_theBodUnchanged() throws Exception{ |  | ||||||
|          |  | ||||||
|         JsonFactory jf = new JsonFactory(new ObjectMapper()); |  | ||||||
|         JsonParser parser = jf.createParser(JSON_WITH_FIELDS_TO_SCRUB); |  | ||||||
|         JsonNode root = parser.readValueAsTree(); |  | ||||||
|          |  | ||||||
|         Config config = new Config(); |  | ||||||
|         config.setFields("xxxx"); |  | ||||||
|         config.setReplacement("*"); |  | ||||||
|         Scrubber scrubber = new ScrubResponseGatewayFilterFactory.Scrubber(config); |  | ||||||
|          |  | ||||||
|         JsonNode scrubbed = Mono.from(scrubber.apply(null, root)).block(); |  | ||||||
|         assertNotNull(scrubbed); |  | ||||||
|         assertNotEquals("*", scrubbed.get("ssn").asText()); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| @ -1,135 +0,0 @@ | |||||||
| package com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories; |  | ||||||
| 
 |  | ||||||
| import java.io.IOException; |  | ||||||
| import java.net.InetSocketAddress; |  | ||||||
| import java.util.Collections; |  | ||||||
| 
 |  | ||||||
| import org.junit.AfterClass; |  | ||||||
| import org.junit.BeforeClass; |  | ||||||
| import org.junit.jupiter.api.Test; |  | ||||||
| import org.slf4j.Logger; |  | ||||||
| import org.slf4j.LoggerFactory; |  | ||||||
| import org.springframework.beans.factory.annotation.Autowired; |  | ||||||
| import org.springframework.boot.CommandLineRunner; |  | ||||||
| import org.springframework.boot.test.context.SpringBootTest; |  | ||||||
| import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; |  | ||||||
| import org.springframework.boot.test.context.TestConfiguration; |  | ||||||
| import org.springframework.boot.web.server.LocalServerPort; |  | ||||||
| import org.springframework.cloud.gateway.filter.factory.SetPathGatewayFilterFactory; |  | ||||||
| import org.springframework.cloud.gateway.route.RouteLocator; |  | ||||||
| import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; |  | ||||||
| import org.springframework.context.annotation.Bean; |  | ||||||
| import org.springframework.context.annotation.Primary; |  | ||||||
| import org.springframework.http.MediaType; |  | ||||||
| import org.springframework.http.client.reactive.ReactorClientHttpConnector; |  | ||||||
| import org.springframework.security.config.web.server.ServerHttpSecurity; |  | ||||||
| import org.springframework.security.web.server.SecurityWebFilterChain; |  | ||||||
| import org.springframework.test.web.reactive.server.WebTestClient; |  | ||||||
| 
 |  | ||||||
| import com.sun.net.httpserver.HttpServer; |  | ||||||
| 
 |  | ||||||
| import reactor.netty.http.client.HttpClient; |  | ||||||
| 
 |  | ||||||
| @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) |  | ||||||
| public class ScrubResponseGatewayFilterLiveTest { |  | ||||||
|      |  | ||||||
|     private static Logger log = LoggerFactory.getLogger(ScrubResponseGatewayFilterLiveTest.class); |  | ||||||
|      |  | ||||||
|     private static final String JSON_WITH_FIELDS_TO_SCRUB = "{\r\n" |  | ||||||
|         + "  \"name\" : \"John Doe\",\r\n" |  | ||||||
|         + "        \"ssn\"  : \"123-45-9999\",\r\n" |  | ||||||
|         + "        \"account\" : \"9999888877770000\"\r\n" |  | ||||||
|         + "}"; |  | ||||||
| 
 |  | ||||||
|     private static final String JSON_WITH_SCRUBBED_FIELDS = "{\r\n" |  | ||||||
|         + "  \"name\" : \"John Doe\",\r\n" |  | ||||||
|         + "        \"ssn\"  : \"*\",\r\n" |  | ||||||
|         + "        \"account\" : \"9999888877770000\"\r\n" |  | ||||||
|         + "}"; |  | ||||||
|      |  | ||||||
|     @LocalServerPort |  | ||||||
|     String port; |  | ||||||
|      |  | ||||||
|     @Autowired |  | ||||||
|     private WebTestClient client; |  | ||||||
|      |  | ||||||
|     @Autowired HttpServer server; |  | ||||||
|      |  | ||||||
|     @Test |  | ||||||
|     public void givenRequestToScrubRoute_thenResponseScrubbed() { |  | ||||||
|                  |  | ||||||
|         client.get() |  | ||||||
|           .uri("/scrub") |  | ||||||
|           .accept(MediaType.APPLICATION_JSON) |  | ||||||
|           .exchange() |  | ||||||
|           .expectStatus() |  | ||||||
|             .is2xxSuccessful() |  | ||||||
|           .expectHeader() |  | ||||||
|             .contentType(MediaType.APPLICATION_JSON) |  | ||||||
|           .expectBody() |  | ||||||
|             .json(JSON_WITH_SCRUBBED_FIELDS); |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|      |  | ||||||
|     @TestConfiguration |  | ||||||
|     public static class TestRoutesConfiguration { |  | ||||||
|          |  | ||||||
|          |  | ||||||
|         @Bean |  | ||||||
|         public RouteLocator scrubSsnRoute(RouteLocatorBuilder builder, ScrubResponseGatewayFilterFactory scrubFilterFactory, SetPathGatewayFilterFactory pathFilterFactory, HttpServer server ) { |  | ||||||
|              |  | ||||||
|             log.info("[I92] Creating scrubSsnRoute..."); |  | ||||||
|              |  | ||||||
|             int mockServerPort = server.getAddress().getPort(); |  | ||||||
|             ScrubResponseGatewayFilterFactory.Config config = new ScrubResponseGatewayFilterFactory.Config(); |  | ||||||
|             config.setFields("ssn"); |  | ||||||
|             config.setReplacement("*"); |  | ||||||
|              |  | ||||||
|             SetPathGatewayFilterFactory.Config pathConfig = new SetPathGatewayFilterFactory.Config(); |  | ||||||
|             pathConfig.setTemplate("/customer"); |  | ||||||
|              |  | ||||||
|             return builder.routes() |  | ||||||
|               .route("scrub_ssn", |  | ||||||
|                  r -> r.path("/scrub") |  | ||||||
|                    .filters(  |  | ||||||
|                       f -> f |  | ||||||
|                         .filter(scrubFilterFactory.apply(config)) |  | ||||||
|                         .filter(pathFilterFactory.apply(pathConfig))) |  | ||||||
|                    .uri("http://localhost:" + mockServerPort )) |  | ||||||
|               .build(); |  | ||||||
|         } |  | ||||||
|          |  | ||||||
|         @Bean |  | ||||||
|         public SecurityWebFilterChain testFilterChain(ServerHttpSecurity http ) { |  | ||||||
|              |  | ||||||
|             // @formatter:off |  | ||||||
|             return http.authorizeExchange() |  | ||||||
|               .anyExchange() |  | ||||||
|                 .permitAll() |  | ||||||
|               .and() |  | ||||||
|               .build(); |  | ||||||
|             // @formatter:on |  | ||||||
|         } |  | ||||||
|          |  | ||||||
|         @Bean |  | ||||||
|         public HttpServer mockServer() throws IOException { |  | ||||||
|              |  | ||||||
|             log.info("[I48] Starting mock server..."); |  | ||||||
|              |  | ||||||
|             HttpServer server = HttpServer.create(new InetSocketAddress(0),0); |  | ||||||
|             server.createContext("/customer", (exchange) ->  { |  | ||||||
|                 exchange.getResponseHeaders().set("Content-Type", "application/json"); |  | ||||||
|                  |  | ||||||
|                 byte[] response = JSON_WITH_FIELDS_TO_SCRUB.getBytes("UTF-8"); |  | ||||||
|                 exchange.sendResponseHeaders(200,response.length); |  | ||||||
|                 exchange.getResponseBody().write(response); |  | ||||||
|             }); |  | ||||||
|              |  | ||||||
|             server.setExecutor(null); |  | ||||||
|             server.start(); |  | ||||||
|              |  | ||||||
|             log.info("[I65] Mock server started. port={}", server.getAddress().getPort()); |  | ||||||
|             return server; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,28 +0,0 @@ | |||||||
| package com.baeldung.springcloudgateway.customfilters.secondservice; |  | ||||||
| 
 |  | ||||||
| import org.junit.jupiter.api.Test; |  | ||||||
| import org.springframework.beans.factory.annotation.Autowired; |  | ||||||
| import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration; |  | ||||||
| import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; |  | ||||||
| import org.springframework.test.web.reactive.server.WebTestClient; |  | ||||||
| 
 |  | ||||||
| import com.baeldung.springcloudgateway.customfilters.secondservice.web.SecondServiceRestController; |  | ||||||
| 
 |  | ||||||
| @WebFluxTest(controllers = SecondServiceRestController.class, |  | ||||||
|         excludeAutoConfiguration = ReactiveSecurityAutoConfiguration.class) |  | ||||||
| public class SecondServiceIntegrationTest { |  | ||||||
| 
 |  | ||||||
|     @Autowired |  | ||||||
|     private WebTestClient webClient; |  | ||||||
| 
 |  | ||||||
|     @Test |  | ||||||
|     public void whenResourceLanguageEndpointCalled_thenRetrievesSpanishLanguageString() throws Exception { |  | ||||||
|         this.webClient.get() |  | ||||||
|             .uri("/resource/language") |  | ||||||
|             .exchange() |  | ||||||
|             .expectStatus() |  | ||||||
|             .isOk() |  | ||||||
|             .expectBody(String.class) |  | ||||||
|             .isEqualTo("es"); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,12 +0,0 @@ | |||||||
| package com.baeldung.springcloudgateway.customfilters.secondservice; |  | ||||||
| 
 |  | ||||||
| import org.junit.jupiter.api.Test; |  | ||||||
| import org.springframework.boot.test.context.SpringBootTest; |  | ||||||
| 
 |  | ||||||
| @SpringBootTest(classes = SecondServiceApplication.class) |  | ||||||
| public class SpringContextTest { |  | ||||||
| 
 |  | ||||||
|     @Test |  | ||||||
|     public void whenSpringContextIsBootstrapped_thenNoExceptions() { |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,31 +0,0 @@ | |||||||
| package com.baeldung.springcloudgateway.customfilters.service; |  | ||||||
| 
 |  | ||||||
| import org.junit.jupiter.api.Test; |  | ||||||
| import org.springframework.beans.factory.annotation.Autowired; |  | ||||||
| import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration; |  | ||||||
| import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; |  | ||||||
| import org.springframework.http.HttpHeaders; |  | ||||||
| import org.springframework.test.web.reactive.server.WebTestClient; |  | ||||||
| 
 |  | ||||||
| import com.baeldung.springcloudgateway.customfilters.service.web.ServiceRestController; |  | ||||||
| 
 |  | ||||||
| @WebFluxTest(controllers = ServiceRestController.class, |  | ||||||
|         excludeAutoConfiguration = ReactiveSecurityAutoConfiguration.class) |  | ||||||
| public class ServiceIntegrationTest { |  | ||||||
| 
 |  | ||||||
|     @Autowired |  | ||||||
|     private WebTestClient webClient; |  | ||||||
| 
 |  | ||||||
|     @Test |  | ||||||
|     public void whenResourceEndpointCalled_thenRetrievesResourceStringWithContentLanguageHeader() throws Exception { |  | ||||||
|         this.webClient.get() |  | ||||||
|             .uri("/resource") |  | ||||||
|             .exchange() |  | ||||||
|             .expectStatus() |  | ||||||
|             .isOk() |  | ||||||
|             .expectHeader() |  | ||||||
|             .valueEquals(HttpHeaders.CONTENT_LANGUAGE, "en") |  | ||||||
|             .expectBody(String.class) |  | ||||||
|             .isEqualTo("Service Resource"); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,12 +0,0 @@ | |||||||
| package com.baeldung.springcloudgateway.customfilters.service; |  | ||||||
| 
 |  | ||||||
| import org.junit.jupiter.api.Test; |  | ||||||
| import org.springframework.boot.test.context.SpringBootTest; |  | ||||||
| 
 |  | ||||||
| @SpringBootTest(classes = ServiceApplication.class) |  | ||||||
| public class SpringContextTest { |  | ||||||
| 
 |  | ||||||
|     @Test |  | ||||||
|     public void whenSpringContextIsBootstrapped_thenNoExceptions() { |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,4 +1,4 @@ | |||||||
| package com.baeldung.springcloudgateway.customfilters.gatewayapp.utils; | package com.baeldung.springcloudgateway.introduction; | ||||||
| 
 | 
 | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| @ -1,109 +0,0 @@ | |||||||
| package com.baeldung.springcloudgateway.rewrite; |  | ||||||
| 
 |  | ||||||
| import static org.junit.Assert.assertTrue; |  | ||||||
| import static org.junit.jupiter.api.Assertions.assertEquals; |  | ||||||
| 
 |  | ||||||
| import java.io.OutputStream; |  | ||||||
| import java.net.InetSocketAddress; |  | ||||||
| 
 |  | ||||||
| import org.junit.AfterClass; |  | ||||||
| import org.junit.jupiter.api.Test; |  | ||||||
| import org.slf4j.Logger; |  | ||||||
| import org.slf4j.LoggerFactory; |  | ||||||
| import org.springframework.beans.factory.annotation.Autowired; |  | ||||||
| import org.springframework.boot.test.context.SpringBootTest; |  | ||||||
| import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; |  | ||||||
| import org.springframework.boot.web.server.LocalServerPort; |  | ||||||
| import org.springframework.test.context.ActiveProfiles; |  | ||||||
| import org.springframework.test.context.DynamicPropertyRegistry; |  | ||||||
| import org.springframework.test.context.DynamicPropertySource; |  | ||||||
| import org.springframework.test.web.reactive.server.WebTestClient; |  | ||||||
| 
 |  | ||||||
| import com.sun.net.httpserver.HttpServer; |  | ||||||
| 
 |  | ||||||
| @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) |  | ||||||
| @ActiveProfiles({ "nosecurity", "url-rewrite" }) |  | ||||||
| class URLRewriteGatewayApplicationLiveTest { |  | ||||||
| 
 |  | ||||||
|     // NOTE for Eclipse users: By default, Eclipse will complain about com.sun.** classes. |  | ||||||
|     // To solve this issue, follow instructions available at the : |  | ||||||
|     // https://stackoverflow.com/questions/13155734/eclipse-cant-recognize-com-sun-net-httpserver-httpserver-package |  | ||||||
|     private static HttpServer mockServer; |  | ||||||
|     private static Logger log = LoggerFactory.getLogger(URLRewriteGatewayApplicationLiveTest.class); |  | ||||||
| 
 |  | ||||||
|     // Create a running HttpServer that echoes back the request URL. |  | ||||||
|     private static HttpServer startTestServer() { |  | ||||||
| 
 |  | ||||||
|         try { |  | ||||||
|             log.info("[I26] Starting mock server"); |  | ||||||
|             mockServer = HttpServer.create(); |  | ||||||
|             mockServer.bind(new InetSocketAddress(0), 0); |  | ||||||
|             mockServer.createContext("/api", (xchg) -> { |  | ||||||
|                 String uri = xchg.getRequestURI() |  | ||||||
|                     .toString(); |  | ||||||
|                 log.info("[I23] Backend called: uri={}", uri); |  | ||||||
|                 xchg.getResponseHeaders() |  | ||||||
|                     .add("Content-Type", "text/plain"); |  | ||||||
|                 xchg.sendResponseHeaders(200, 0); |  | ||||||
|                 OutputStream os = xchg.getResponseBody(); |  | ||||||
|                 os.write(uri.getBytes()); |  | ||||||
|                 os.flush(); |  | ||||||
|                 os.close(); |  | ||||||
|             }); |  | ||||||
| 
 |  | ||||||
|             mockServer.start(); |  | ||||||
|             InetSocketAddress localAddr = mockServer.getAddress(); |  | ||||||
|             log.info("[I36] mock server started: local address={}", localAddr); |  | ||||||
|              |  | ||||||
|             return mockServer; |  | ||||||
|         } catch (Exception ex) { |  | ||||||
|             throw new RuntimeException(ex); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // TIP: https://www.baeldung.com/spring-dynamicpropertysource |  | ||||||
|     @DynamicPropertySource |  | ||||||
|     static void registerBackendServer(DynamicPropertyRegistry registry) { |  | ||||||
|         registry.add("rewrite.backend.uri", () -> { |  | ||||||
|             HttpServer s = startTestServer(); |  | ||||||
|             return "http://localhost:" + s.getAddress().getPort(); |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @AfterClass |  | ||||||
|     public static void stopMockBackend() throws Exception { |  | ||||||
|         log.info("[I40] Shutdown mock http server"); |  | ||||||
|         mockServer.stop(5); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @LocalServerPort |  | ||||||
|     private int localPort; |  | ||||||
| 
 |  | ||||||
|     @Test |  | ||||||
|     void testWhenApiCall_thenRewriteSuccess(@Autowired WebTestClient webClient) { |  | ||||||
|         webClient.get() |  | ||||||
|           .uri("http://localhost:" + localPort + "/v1/customer/customer1") |  | ||||||
|           .exchange() |  | ||||||
|           .expectBody() |  | ||||||
|           .consumeWith((result) -> { |  | ||||||
|               String body = new String(result.getResponseBody()); |  | ||||||
|               log.info("[I99] body={}", body); |  | ||||||
|               assertEquals("/api/customer1", body); |  | ||||||
|           }); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Test |  | ||||||
|     void testWhenDslCall_thenRewriteSuccess(@Autowired WebTestClient webClient) { |  | ||||||
|         webClient.get() |  | ||||||
|           .uri("http://localhost:" + localPort + "/v2/zip/123456") |  | ||||||
|           .exchange() |  | ||||||
|           .expectBody() |  | ||||||
|           .consumeWith((result) -> { |  | ||||||
|               String body = new String(result.getResponseBody()); |  | ||||||
|               log.info("[I99] body={}", body); |  | ||||||
|               assertTrue(body.matches("/api/zip/123456-\\d{3}")); |  | ||||||
|           }); |  | ||||||
|     } |  | ||||||
|      |  | ||||||
| } |  | ||||||
| @ -1,64 +0,0 @@ | |||||||
| package com.baeldung.springcloudgateway.webfilters; |  | ||||||
| 
 |  | ||||||
| import org.junit.After; |  | ||||||
| import org.junit.Before; |  | ||||||
| import org.junit.jupiter.api.RepeatedTest; |  | ||||||
| import org.slf4j.Logger; |  | ||||||
| import org.slf4j.LoggerFactory; |  | ||||||
| import org.springframework.beans.factory.annotation.Autowired; |  | ||||||
| import org.springframework.beans.factory.annotation.Value; |  | ||||||
| import org.springframework.boot.test.context.SpringBootTest; |  | ||||||
| import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; |  | ||||||
| import org.springframework.boot.test.context.TestConfiguration; |  | ||||||
| import org.springframework.boot.test.web.client.TestRestTemplate; |  | ||||||
| import org.springframework.boot.web.server.LocalServerPort; |  | ||||||
| import org.springframework.http.ResponseEntity; |  | ||||||
| import org.springframework.test.context.ActiveProfiles; |  | ||||||
| 
 |  | ||||||
| import redis.embedded.RedisServer; |  | ||||||
| 
 |  | ||||||
| @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) |  | ||||||
| @ActiveProfiles("webfilters") |  | ||||||
| @TestConfiguration |  | ||||||
| public class RedisWebFilterFactoriesLiveTest { |  | ||||||
|      |  | ||||||
|     private static final Logger LOGGER = LoggerFactory.getLogger(RedisWebFilterFactoriesLiveTest.class); |  | ||||||
|      |  | ||||||
|     private RedisServer redisServer; |  | ||||||
|      |  | ||||||
|     public RedisWebFilterFactoriesLiveTest() { |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Before |  | ||||||
|     public void postConstruct() { |  | ||||||
|         this.redisServer = new RedisServer(6379); |  | ||||||
|         redisServer.start();     |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     @LocalServerPort |  | ||||||
|     String port; |  | ||||||
| 
 |  | ||||||
|     @Autowired |  | ||||||
|     private TestRestTemplate restTemplate; |  | ||||||
| 
 |  | ||||||
|     @Autowired |  | ||||||
|     TestRestTemplate template; |  | ||||||
|   |  | ||||||
|     @RepeatedTest(25) |  | ||||||
|     public void whenCallRedisGetThroughGateway_thenOKStatusOrIsReceived() { |  | ||||||
|         String url = "http://localhost:" + port + "/redis/get"; |  | ||||||
| 
 |  | ||||||
|         ResponseEntity<String> r = restTemplate.getForEntity(url, String.class); |  | ||||||
|         // assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); |  | ||||||
| 
 |  | ||||||
|         LOGGER.info("Received: status->{}, reason->{}, remaining->{}",  |  | ||||||
|           r.getStatusCodeValue(), r.getStatusCode().getReasonPhrase(),  |  | ||||||
|           r.getHeaders().get("X-RateLimit-Remaining")); |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     @After |  | ||||||
|     public void preDestroy() { |  | ||||||
|         redisServer.stop(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| @ -1,136 +0,0 @@ | |||||||
| package com.baeldung.springcloudgateway.webfilters; |  | ||||||
| 
 |  | ||||||
| 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 org.assertj.core.api.Condition; |  | ||||||
| import org.json.JSONException; |  | ||||||
| import org.json.JSONObject; |  | ||||||
| import org.junit.jupiter.api.BeforeEach; |  | ||||||
| import org.junit.jupiter.api.Test; |  | ||||||
| import org.springframework.beans.factory.annotation.Autowired; |  | ||||||
| import org.springframework.boot.test.context.SpringBootTest; |  | ||||||
| import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; |  | ||||||
| import org.springframework.boot.test.web.client.TestRestTemplate; |  | ||||||
| import org.springframework.boot.web.server.LocalServerPort; |  | ||||||
| import org.springframework.http.HttpEntity; |  | ||||||
| import org.springframework.http.HttpHeaders; |  | ||||||
| import org.springframework.http.HttpMethod; |  | ||||||
| import org.springframework.http.HttpStatus; |  | ||||||
| import org.springframework.http.ResponseEntity; |  | ||||||
| import org.springframework.test.context.ActiveProfiles; |  | ||||||
| import org.springframework.test.web.reactive.server.WebTestClient; |  | ||||||
| import org.springframework.test.web.reactive.server.WebTestClient.ResponseSpec; |  | ||||||
| 
 |  | ||||||
| @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) |  | ||||||
| @ActiveProfiles("webfilters") |  | ||||||
| public class WebFilterFactoriesLiveTest { |  | ||||||
| 
 |  | ||||||
|     @LocalServerPort |  | ||||||
|     String port; |  | ||||||
| 
 |  | ||||||
|     @Autowired |  | ||||||
|     private WebTestClient client; |  | ||||||
| 
 |  | ||||||
|     @Autowired |  | ||||||
|     private TestRestTemplate restTemplate; |  | ||||||
| 
 |  | ||||||
|     @BeforeEach |  | ||||||
|     public void configureClient() { |  | ||||||
|         client = WebTestClient.bindToServer() |  | ||||||
|           .baseUrl("http://localhost:" + port) |  | ||||||
|           .build(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Test |  | ||||||
|     public void whenCallGetThroughGateway_thenAllHTTPRequestHeadersParametersAreSet() throws JSONException { |  | ||||||
|         String url = "http://localhost:" + port + "/get"; |  | ||||||
|         ResponseEntity<String> response = restTemplate.getForEntity(url, String.class); |  | ||||||
|         assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); |  | ||||||
| 
 |  | ||||||
|         JSONObject json = new JSONObject(response.getBody()); |  | ||||||
|         JSONObject headers = json.getJSONObject("headers"); |  | ||||||
|         assertThat(headers.getString("My-Header-Good")).isEqualTo("Good"); |  | ||||||
|         assertThat(headers.getString("My-Header-Bad")).isEqualTo("Good"); |  | ||||||
|         assertThat(headers.getString("My-Header-Set")).isEqualTo("Set"); |  | ||||||
|         assertTrue(headers.isNull("My-Header-Remove")); |  | ||||||
|         JSONObject vars = json.getJSONObject("args"); |  | ||||||
|         assertThat(vars.getString("var")).isEqualTo("good"); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Test |  | ||||||
|     public void whenCallHeaderPostThroughGateway_thenAllHTTPResponseHeadersAreSet() { |  | ||||||
|         ResponseSpec response = client.post() |  | ||||||
|           .uri("/header/post") |  | ||||||
|           .exchange(); |  | ||||||
| 
 |  | ||||||
|         response.expectStatus() |  | ||||||
|           .isOk() |  | ||||||
|           .expectHeader() |  | ||||||
|           .valueEquals("My-Header-Rewrite", "password=***") |  | ||||||
|           .expectHeader() |  | ||||||
|           .valueEquals("My-Header-Set", "Set") |  | ||||||
|           .expectHeader() |  | ||||||
|           .valueEquals("My-Header-Good", "Good") |  | ||||||
|           .expectHeader() |  | ||||||
|           .doesNotExist("My-Header-Remove"); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Test |  | ||||||
|     public void whenCallPostThroughGateway_thenBodyIsRetrieved() throws JSONException { |  | ||||||
|         String url = "http://localhost:" + port + "/post"; |  | ||||||
| 
 |  | ||||||
|         HttpEntity<String> entity = new HttpEntity<>("content", new HttpHeaders()); |  | ||||||
| 
 |  | ||||||
|         ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class); |  | ||||||
|         assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); |  | ||||||
| 
 |  | ||||||
|         JSONObject json = new JSONObject(response.getBody()); |  | ||||||
|         JSONObject data = json.getJSONObject("json"); |  | ||||||
|         assertThat(data.getString("message")).isEqualTo("CONTENT"); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Test |  | ||||||
|     public void whenCallPutThroughGateway_thenBodyIsRetrieved() throws JSONException { |  | ||||||
|         String url = "http://localhost:" + port + "/put"; |  | ||||||
| 
 |  | ||||||
|         HttpEntity<String> entity = new HttpEntity<>("CONTENT", new HttpHeaders()); |  | ||||||
| 
 |  | ||||||
|         ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.PUT, entity, String.class); |  | ||||||
|         assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); |  | ||||||
| 
 |  | ||||||
|         JSONObject json = new JSONObject(response.getBody()); |  | ||||||
|         assertThat(json.getString("message")).isEqualTo("New Body"); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Test |  | ||||||
|     public void whenCallDeleteThroughGateway_thenIsUnauthorizedCodeIsSet() { |  | ||||||
|         ResponseSpec response = client.delete() |  | ||||||
|           .uri("/delete") |  | ||||||
|           .exchange(); |  | ||||||
| 
 |  | ||||||
|         response.expectStatus() |  | ||||||
|           .isUnauthorized(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Test |  | ||||||
|     public void whenCallFakePostThroughGateway_thenIsUnauthorizedCodeIsSet() { |  | ||||||
|         ResponseSpec response = client.post() |  | ||||||
|           .uri("/fake/post") |  | ||||||
|           .exchange(); |  | ||||||
| 
 |  | ||||||
|         response.expectStatus() |  | ||||||
|           .is3xxRedirection(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Test |  | ||||||
|     public void whenCallStatus504ThroughGateway_thenCircuitBreakerIsExecuted() throws JSONException { |  | ||||||
|         String url = "http://localhost:" + port + "/status/504"; |  | ||||||
|         ResponseEntity<String> response = restTemplate.getForEntity(url, String.class); |  | ||||||
| 
 |  | ||||||
|         JSONObject json = new JSONObject(response.getBody()); |  | ||||||
|         assertThat(json.getString("url")).contains("anything"); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,203 +0,0 @@ | |||||||
| { |  | ||||||
| 	"info": { |  | ||||||
| 		"_postman_id": "b3d00e23-c2cd-40ce-a90b-673efb25e5c0", |  | ||||||
| 		"name": "Baeldung - OAuth", |  | ||||||
| 		"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" |  | ||||||
| 	}, |  | ||||||
| 	"item": [ |  | ||||||
| 		{ |  | ||||||
| 			"name": "Token", |  | ||||||
| 			"event": [ |  | ||||||
| 				{ |  | ||||||
| 					"listen": "test", |  | ||||||
| 					"script": { |  | ||||||
| 						"exec": [ |  | ||||||
| 							"var jsonData = pm.response.json();\r", |  | ||||||
| 							"pm.environment.set(\"access_token\", jsonData.access_token);\r", |  | ||||||
| 							"pm.environment.set(\"refresh_token\", jsonData.refresh_token);\r", |  | ||||||
| 							"pm.environment.set(\"backend_token\", \"Bearer \" + jsonData.access_token);" |  | ||||||
| 						], |  | ||||||
| 						"type": "text/javascript" |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			], |  | ||||||
| 			"request": { |  | ||||||
| 				"method": "POST", |  | ||||||
| 				"header": [], |  | ||||||
| 				"body": { |  | ||||||
| 					"mode": "urlencoded", |  | ||||||
| 					"urlencoded": [ |  | ||||||
| 						{ |  | ||||||
| 							"key": "client_id", |  | ||||||
| 							"value": "{{client_id}}", |  | ||||||
| 							"type": "text" |  | ||||||
| 						}, |  | ||||||
| 						{ |  | ||||||
| 							"key": "client_secret", |  | ||||||
| 							"value": "{{client_secret}}", |  | ||||||
| 							"type": "text" |  | ||||||
| 						}, |  | ||||||
| 						{ |  | ||||||
| 							"key": "grant_type", |  | ||||||
| 							"value": "password", |  | ||||||
| 							"type": "text" |  | ||||||
| 						}, |  | ||||||
| 						{ |  | ||||||
| 							"key": "scope", |  | ||||||
| 							"value": "email roles profile", |  | ||||||
| 							"type": "text" |  | ||||||
| 						}, |  | ||||||
| 						{ |  | ||||||
| 							"key": "username", |  | ||||||
| 							"value": "maxwell.smart", |  | ||||||
| 							"type": "text" |  | ||||||
| 						}, |  | ||||||
| 						{ |  | ||||||
| 							"key": "password", |  | ||||||
| 							"value": "1234", |  | ||||||
| 							"type": "text" |  | ||||||
| 						} |  | ||||||
| 					] |  | ||||||
| 				}, |  | ||||||
| 				"url": { |  | ||||||
| 					"raw": "{{keycloack_base}}/token", |  | ||||||
| 					"host": [ |  | ||||||
| 						"{{keycloack_base}}" |  | ||||||
| 					], |  | ||||||
| 					"path": [ |  | ||||||
| 						"token" |  | ||||||
| 					] |  | ||||||
| 				} |  | ||||||
| 			}, |  | ||||||
| 			"response": [] |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			"name": "Quote", |  | ||||||
| 			"protocolProfileBehavior": { |  | ||||||
| 				"disabledSystemHeaders": { |  | ||||||
| 					"accept": true |  | ||||||
| 				} |  | ||||||
| 			}, |  | ||||||
| 			"request": { |  | ||||||
| 				"auth": { |  | ||||||
| 					"type": "bearer", |  | ||||||
| 					"bearer": [ |  | ||||||
| 						{ |  | ||||||
| 							"key": "token", |  | ||||||
| 							"value": "{{access_token}}", |  | ||||||
| 							"type": "string" |  | ||||||
| 						} |  | ||||||
| 					] |  | ||||||
| 				}, |  | ||||||
| 				"method": "GET", |  | ||||||
| 				"header": [ |  | ||||||
| 					{ |  | ||||||
| 						"key": "Accept", |  | ||||||
| 						"value": "application/json", |  | ||||||
| 						"type": "text" |  | ||||||
| 					} |  | ||||||
| 				], |  | ||||||
| 				"url": { |  | ||||||
| 					"raw": "http://localhost:8085/quotes/:symbol", |  | ||||||
| 					"protocol": "http", |  | ||||||
| 					"host": [ |  | ||||||
| 						"localhost" |  | ||||||
| 					], |  | ||||||
| 					"port": "8085", |  | ||||||
| 					"path": [ |  | ||||||
| 						"quotes", |  | ||||||
| 						":symbol" |  | ||||||
| 					], |  | ||||||
| 					"variable": [ |  | ||||||
| 						{ |  | ||||||
| 							"key": "symbol", |  | ||||||
| 							"value": "IBM" |  | ||||||
| 						} |  | ||||||
| 					] |  | ||||||
| 				} |  | ||||||
| 			}, |  | ||||||
| 			"response": [] |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			"name": "Quote via Gateway", |  | ||||||
| 			"protocolProfileBehavior": { |  | ||||||
| 				"disabledSystemHeaders": { |  | ||||||
| 					"accept": true |  | ||||||
| 				} |  | ||||||
| 			}, |  | ||||||
| 			"request": { |  | ||||||
| 				"auth": { |  | ||||||
| 					"type": "bearer", |  | ||||||
| 					"bearer": [ |  | ||||||
| 						{ |  | ||||||
| 							"key": "token", |  | ||||||
| 							"value": "{{access_token}}", |  | ||||||
| 							"type": "string" |  | ||||||
| 						} |  | ||||||
| 					] |  | ||||||
| 				}, |  | ||||||
| 				"method": "GET", |  | ||||||
| 				"header": [ |  | ||||||
| 					{ |  | ||||||
| 						"key": "Accept", |  | ||||||
| 						"value": "application/json", |  | ||||||
| 						"type": "text" |  | ||||||
| 					} |  | ||||||
| 				], |  | ||||||
| 				"url": { |  | ||||||
| 					"raw": "http://localhost:8086/quotes/:symbol", |  | ||||||
| 					"protocol": "http", |  | ||||||
| 					"host": [ |  | ||||||
| 						"localhost" |  | ||||||
| 					], |  | ||||||
| 					"port": "8086", |  | ||||||
| 					"path": [ |  | ||||||
| 						"quotes", |  | ||||||
| 						":symbol" |  | ||||||
| 					], |  | ||||||
| 					"variable": [ |  | ||||||
| 						{ |  | ||||||
| 							"key": "symbol", |  | ||||||
| 							"value": "IBM" |  | ||||||
| 						} |  | ||||||
| 					] |  | ||||||
| 				} |  | ||||||
| 			}, |  | ||||||
| 			"response": [] |  | ||||||
| 		} |  | ||||||
| 	], |  | ||||||
| 	"event": [ |  | ||||||
| 		{ |  | ||||||
| 			"listen": "prerequest", |  | ||||||
| 			"script": { |  | ||||||
| 				"type": "text/javascript", |  | ||||||
| 				"exec": [ |  | ||||||
| 					"" |  | ||||||
| 				] |  | ||||||
| 			} |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			"listen": "test", |  | ||||||
| 			"script": { |  | ||||||
| 				"type": "text/javascript", |  | ||||||
| 				"exec": [ |  | ||||||
| 					"" |  | ||||||
| 				] |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	], |  | ||||||
| 	"variable": [ |  | ||||||
| 		{ |  | ||||||
| 			"key": "keycloack_base", |  | ||||||
| 			"value": "http://localhost:8083/auth/realms/baeldung/protocol/openid-connect" |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			"key": "client_id", |  | ||||||
| 			"value": "quotes-client" |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			"key": "client_secret", |  | ||||||
| 			"value": "56be94c8-b20a-4374-899c-e39cb022d3f8" |  | ||||||
| 		} |  | ||||||
| 	] |  | ||||||
| } |  | ||||||
| @ -1,7 +1,7 @@ | |||||||
| <?xml version="1.0" encoding="UTF-8"?> | <?xml version="1.0" encoding="UTF-8"?> | ||||||
| <configuration> | <configuration> | ||||||
|     <appender name="LISTAPPENDER" |     <appender name="LISTAPPENDER" | ||||||
|         class="com.baeldung.springcloudgateway.customfilters.gatewayapp.utils.LoggerListAppender"> |         class="com.baeldung.springcloudgateway.introduction.LoggerListAppender"> | ||||||
|     </appender> |     </appender> | ||||||
|     <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> |     <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> | ||||||
|         <encoder> |         <encoder> | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user