I just announced the new Spring 5 modules in REST With Spring:

>> CHECK OUT THE COURSE

1. Overview

In this article, we’ll explore the main features of the Spring Cloud Gateway project, a new API based on Spring 5, Spring Boot 2 and Project Reactor.

The tool provides out-of-the-box routing mechanisms often used in microservices applications as a way of hiding multiple services behind a single facade.

2. Routing Handler

Being focused on routing requests, the Spring Cloud Gateway forwards requests to a Gateway Handler Mapping – which determines what should be done with requests matching a specific route.

Let’s start with a quick example of how to the Gateway Handler resolves route configurations by using RouteLocator:

@Bean
public RouteLocator routingConfig() {
    return Routes.locator()
      .route("baeldung")
      .uri("http://baeldung.com")
      .predicate(host("**.baeldung.com"))
      .and()
      .route("myOtherRouting")
      .id("myOtherID")
      .uri("http://othersite.com")
      .predicate(get("**.baeldung.com"))
      .and()
      .build();
}

Notice how we made use of the main building blocks of this API:

  • Route –  the primary API of the gateway. It is defined by a given identification (ID), a destination (URI) and set of predicates and filters
  • Predicate – a Java 8’s Predicate – which is used for matching HTTP requests using headers, methods or parameters
  • Filter – a standard Spring’s WebFilter

3. Dynamic Routing

Just like Zuul, Spring Cloud Gateway provides means for routing requests to different services.

The routing configuration can be created by using pure Java (RouteLocator, as shown in the example in section 2.1) or by using properties configuration:

spring:
  application:
    name: gateway-service  
  cloud:
    gateway:
      routes:
      - id: baeldung
        uri: baeldung.com
      - id: myOtherRouting
        uri: localhost:9999

4. Routing Factories 

Spring Cloud Gateway matches routes using the Spring WebFlux HandlerMapping infrastructure.

It also includes many built-in Route Predicate Factories. All of these predicates match different attributes of the HTTP request. Multiple Route Predicate Factories can be combined via the logical “and”.

Route matching can be applied both programmatically or via configuration properties file using a different type of Route Predicate Factories.

4.1. Before Route Predicate Factory

The Before Route Predicate Factory takes one parameter: a datetime. This predicate matches requests that happen before the current datetime:

spring:
  cloud:
    gateway:
      routes:
      - id: before_route
        uri: http://baeldung.com
        predicates:
        - Before=2017-09-11T17:42:47.789-07:00[America/Alaska]

The Java configuration can be represented as:

//..route definition 
.id("before_route")
.uri("http://baeldung.com")
.predicate(before(LocalDateTime.now().atZone(ZoneId.systemDefault()))

4.2. Between Route Predicate Factory

The Between Route Predicate Factory takes two parameters: datetime1, and datetime2. This predicate matches requests that happen after datetime1 (inclusive) and before datetime2 (exclusive). The datetime2 parameter must be after datetime1: 

spring:
  cloud:
    gateway:
      routes:
      - id: between_route
        uri: http://baeldung.com
        predicates:
        - Between=2017-09-10T17:42:47.789-07:00[America/Alaska], 2017-09-11T17:42:47.789-07:00[America/Alaska]

And the Java configuration looks like this:

ZonedDateTime datetime1 = LocalDateTime.now().minusDays(1).atZone(ZoneId.systemDefault());
ZonedDateTime datetime2 = LocalDateTime.now().atZone(ZoneId.systemDefault())
//..route definition
.id("between_route")
.uri("http://baeldung.com")
.predicate(between(datetime1, datetime2))

4.3. Header Route Predicate Factory

The Header Route Predicate Factory takes two parameters: the header name, and a regular expression. This predicate matches a header matching the regular expression: 

spring:
  cloud:
    gateway:
      routes:
      - id: header_route
        uri: http://baeldung.com
        predicates:
        - Header=X-Request-Id, \d+

The Java configuration can be represented as:

//..route definition
.id("header_route")
.uri("http://baeldung.com")
.predicate(header("X-Request-Id", "\d+"))

4.4. Host Route Predicate Factor

The Host Route Predicate Factory takes one parameter: the hostname pattern. The pattern is an Ant-style pattern with “.” as the separator.

This predicate matches the Host header with the given the pattern: 

spring:
  cloud:
    gateway:
      routes:
      - id: host_route
        uri: http://baeldung.com
        predicates:
        - Host=**.baeldung.com

Here’s the Java configuration alternative:

//..route definition
.id("host_route")
.uri("http://baeldung.com")
.predicate(host("**.baeldung.com"))

4.5. Method Route Predicate Factory

The Method Route Predicate Factory takes one parameter: the HTTP method to match: 

spring:
  cloud:
    gateway:
      routes:
      - id: method_route
        uri: http://baeldung.com
        predicates:
        - Method=GET

The Java configuration can be represented as:

//..route definition
.id("method_route")
.uri("http://baeldung.com")
.predicate(method("GET"))

4.6. Path Route Predicate Factory

The Path Route Predicate Factory takes one parameter: a Spring PathMatcher pattern: 

spring:
  cloud:
    gateway:
      routes:
      - id: path_route
        uri: http://baeldung.com
        predicates:
        - Path=/articles/{articleId}

The Java configuration:

//..route definition
.id("path_route")
.uri("http://baeldung.com")
.predicate(path("/articles/"+articleId))

4.7. Query Route Predicate Factory

The Query Route Predicate Factory takes two parameters: a required param and an optional regexp: 

spring:
  cloud:
    gateway:
      routes:
      - id: query_route
        uri: http://baeldung.com
        predicates:
        - Query=articleId, \w

And the Java configuration:

//..route definition
.id("query_route")
.uri("http://baeldung.com")
.predicate(query("articleId", "\w"))

4.8. RemoteAddr Route Predicate Factory

The RemoteAddr Route Predicate Factory takes a list (minimum of 1) of CIDR-notation strings, e.g., 192.168.0.1/16 (where 192.168.0.1 is an IP address, and 16 is a subnet mask): 

spring:
  cloud:
    gateway:
      routes:
      - id: remoteaddr_route
        uri: http://baeldung.com
        predicates:
        - RemoteAddr=192.168.1.1/24

And the corresponding Java configuration:

//..route definition
.id("remoteaddr_route")
.uri("http://baeldung.com")
.predicate(remoteAddr("192.168.1.1/24"))

5. WebFilter Factories

Route filters make the modification of the incoming HTTP request or outgoing HTTP response possible.

Spring Cloud Gateway includes many built-in WebFilter Factories.

5.1. AddRequestHeader WebFilter Factory 

The AddRequestHeader WebFilter Factory takes a name and value parameter: 

spring:
  cloud:
    gateway:
      routes:
      - id: addrequestheader_route
        uri: http://baeldung.com
        predicates:
        - Path=/articles
        filters:
        - AddRequestHeader=X-SomeHeader, bael

Here’s the corresponding Java config:

//...route definition
.route("addrequestheader_route")
.uri("http://baeldung.com")
.predicate(path("/articles"))
.add(addRequestHeader("X-SomeHeader", "bael"))

5.2. AddRequestParameter WebFilter Factory

The AddRequestParameter WebFilter Factory takes a name and value parameter: 

spring:
  cloud:
    gateway:
      routes:
      - id: addrequestparameter_route
        uri: http://baeldung.com
        predicates:
        - Path=/articles
        filters:
        - AddRequestParameter=foo, bar

The corresponding Java configuration:

//...route definition
.route("addrequestparameter_route")
.uri("http://baeldung.com")
.predicate(path("/articles"))
.add(addRequestParameter("foo", "bar"))

5.3. AddResponseHeader WebFilter Factory

The AddResponseHeader WebFilter Factory takes a name and value parameter: 

spring:
  cloud:
    gateway:
      routes:
      - id: addrequestheader_route
        uri: http://baeldung.com
        predicates:
        - Path=/articles
        filters:
        - AddResponseHeader=X-SomeHeader, Bar

The corresponding Java configuration:

//...route definition
.route("addrequestheader_route")
.uri("http://baeldung.com")
.predicate(path("/articles"))
.add(addResponseHeader("X-SomeHeader", "Bar"))

5.4. Circuit Breaker WebFilter Factory

Hystrix is used as Circuit-Breaker WebFilter Factory and takes a single name parameter, which is the name of the Hystrix command: 

spring:
  cloud:
    gateway:
      routes:
      - id: hystrix_route
        uri: http://baeldung.com
        predicates:
        - Path=/articles
        filters:
        - Hystrix=someCommand

The corresponding Java configuration:

//...route definition
.route("hystrix_route")
.uri("http://baeldung.com")
.predicate(path("/articles"))
.add(hystrix("someCommand"))

5.5. RedirectTo WebFilter Factory 

The RedirectTo WebFilter Factory takes a status and a URL parameter. The status should be a 300 redirect HTTP code, such as 301: 

spring:
  cloud:
    gateway:
      routes:
      - id: redirectto_route
        uri: http://baeldung.com
        predicates:
        - Path=/articles
        filters:
        - RedirectTo=302, http://foo.bar

And the corresponding Java configuration:

//...route definition
.route("redirectto_route")
.uri("http://baeldung.com")
.predicate(path("/articles"))
.add(redirectTo("302", "http://foo.bar"))

5.6. RewritePath WebFilter Factory

The RewritePath WebFilter Factory takes a path regexp parameter and a replacement parameter. This uses Java regular expressions to rewrite the request path.

Here is a configuration example: 

spring:
  cloud:
    gateway:
      routes:
      - id: rewritepath_route
        uri: http://baeldung.com
        predicates: 
        - Path=/articles/**
        filters:
        - RewritePath=/articles/(?<articleId>.*), /$\{articleId}

The Java configuration can be represented as:

//...route definition
.route("rewritepath_route")
.uri("http://baeldung.com")
.predicate(path("/articles"))
.add(rewritePath("(?<articleId>.*)", articleId))

5.7. RequestRateLimiter WebFilter Factory

The RequestRateLimiter WebFilter Factory takes three parameters: replenishRate, capacity, and keyResolverName.

  • replenishRate – represents how many requests per second do you want a user to be allowed to do
  • capacity – defines how much bursting capacity would be allowed
  • keyResolverName – is the name of a bean that implements the KeyResolver interface

The KeyResolver interface allows pluggable strategies to derive the key for limiting requests:

spring:
  cloud:
    gateway:
      routes:
      - id: requestratelimiter_route
        uri: http://baeldung.com
        predicates:
        - Path=/articles
        filters:
        - RequestRateLimiter=10, 50, userKeyResolver

The Java configuration can be represented as:

//...route definition
.route("requestratelimiter_route")
.uri("http://baeldung.com")
.predicate(path("/articles"))
.add(requestRateLimiter("10", "50", "UserKeyResolver"))

6. Spring Cloud DiscoveryClient Support

Spring Cloud Gateway can be easily integrated with Service Discovery and Registry libraries, such as Eureka Server and Consul:

@Configuration
@EnableDiscoveryClient
public class GatewayDiscoveryConfiguration {
 
    @Bean
    public DiscoveryClientRouteDefinitionLocator 
      discoveryClientRouteLocator(DiscoveryClient discoveryClient) {
 
        return new DiscoveryClientRouteDefinitionLocator(discoveryClient);
    }
}

6.1. LoadBalancerClient Filter

The LoadBalancerClientFilter looks for a URI in the exchange attribute property using ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR.

If the URL has a lb scheme (e.g., lb://baeldung-service) it’ll use the Spring Cloud LoadBalancerClient to resolve the name (i.e., baeldung-service) to an actual host and port.

The unmodified original URL is placed in the ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR attribute.

7. Monitoring

Spring Cloud Gateway makes use of the Actuator API, a well-known Spring-Boot library that provides several out-of-the-box services for monitoring the application.

Once the Actuator API is installed and configured, the gateway monitoring features can be visualized by accessing /gateway/ endpoint.

8. Implementation

We’ll now create a simple example of the usage of Spring Cloud Gateway as a proxy server using the path predicate.

8.1. Dependencies

The Spring Cloud Gateway is located at Spring Milestones repository, currently on version 2.0.0.M2. This is also the version we’re using here.

Let’s define the Maven dependencies used in this example:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-actuator</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-gateway-core</artifactId>
</dependency>

8.2. Code Implementation

And now we create a simple routing configuration in the application.yml file:

spring:
  cloud:
    gateway:
      routes:
      - id: baeldung_route
        uri: http://baeldung.com
        predicates:
        - Path=/baeldung/
management:
  security:
    enabled: false

And the Gateway application code:

@SpringBootApplication
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}

After the application starts, we can access the url: “http://localhost/admin/gateway/routes/baeldung_route” to check all routing configuration created:

{
    "id":"baeldung_route",
    "predicates":[{
        "name":"Path",
        "args":{"_genkey_0":"/baeldung"}
    }],
    "filters":[],
    "uri":"http://baeldung.com",
    "order":0
}

We see that the relative url: “/baeldung” is configured as a route, so hitting the url “http://localhost/baeldung” we’ll be redirected to  “http://baeldung.com“, as was configured in our example.

9. Conclusion

In this article, we explored some of the features and components that are part of Spring Cloud Gateway. This new API provides out-of-the-box tools for gateway and proxy support.

The examples presented here can be found in our GitHub repository.

I just announced the new Spring 5 modules in REST With Spring:

>> CHECK OUT THE LESSONS

Sort by:   newest | oldest | most voted
Ismo
Guest

Hi,

nice tutorial ! I have some questions about the Spring Cloud Gateway. Is Spring Cloud Gateway supported with “loadBalancing” like the Spring Zuul Gateway with Ribbon? Does the Spring Cloud Gateway supports FIlter like Zuul ? And is the Spring Cloud Gateway non-blocking ?

Thanks and greets.

Grzegorz Piwowarek
Editor

Spring Cloud Gateway is pretty much a facade for hiding your microservices architecture and exposing them as one thing – so this works on the server-side of things. Of course, you can throw in Ribbon which works on the client-side (at least this is how I understand it)

Spring Cloud Gateway supports filters like Zuul.
Also, what do you mean when you ask if it’s non-blocking? From the client side, it’s a standard HTTP call, when making an HTTP request, you can wrap perform it asynchronously but that’s your responsibility

Ismo
Guest

Hi Grzegorz,

i mean the “LoadBalancing” on the Api-Gateway, not client-side. Zuul 1 can loadbalancing automatically with Ribbon. My question was, if the Spring-Cloud-Gateway do this also with “Ribbon” under the hood automatically ? And about the non-blocking thing, Netflix Zuul 2 (it will be released) will be full non-blocking with RxJava. My question about the non-blocking for Spring-Cloud-Gateway was, can i use for example the “Reactor WebClient” to route requests manually etc. ?

Greets

Grzegorz Piwowarek
Editor

Isn’t the Ribbon’s load balancing done on the client side?
As far as I’m aware, no server-side load balancing functionality from the Spring Cloud Gateway and it’s implemented in the standard “blocking” thread-per-request way. I’m not 100% sure but if it was not the case, they would be writing everywhere about this 🙂

Of course, you can use the Reactive WebClient with it

Anton
Guest

Nothing is said about body modifying, neither request, nor response. Is it possible?

Grzegorz Piwowarek
Editor

Yes, you can do that just like in Zuul by implementing custom filters. Actually, it’s exactly the same interface as used in Zuul – ZuulFilter

Anton
Guest

As I can see, there are only GatewayFilterFactory and GlobalFilter and GatewayFilter interfaces to implement. But as I can implement (theoretically) request body modification, I don’t see posiblity to change RxNetty-based response body – when I try, I’m getting “java.lang.IllegalStateException: Only one connection receive subscriber allowed”. Do I miss smth?

Grzegorz Piwowarek
Editor

hmm, I messed up different projects indeed.

And when it comes to the RxNetty case, it looks like a bug – you might want to start an issue on Gateway’s GitHub

Pravin
Guest

I have written custom filters using gateway filter factory. How to make these filters execute before executing default routing.

Grzegorz Piwowarek
Editor

That’s a very good point – I was wondering about the same but it looks like it’s not yet supported

Anton
Guest

Interested in body modification, see WeirdBob kind explanations: https://github.com/spring-cloud/spring-cloud-gateway/issues/47 and his short but comprehensive example: https://gist.github.com/WeirdBob/b25569d461f0f54444d2c0eab51f3c48

I’m new to Spring 5 and rx, but Spencer’s code is pretty clean and self-explanatory. Read, learn, try.

Anton
Guest
Travis
Guest

I am assuming there is a good integration point to hook in Spring Security to Auth before a request is routed ?