7. Global Filters

The GlobalFilter interface has the same signature as GatewayFilter. These are special filters that are conditionally applied to all routes.

This interface and its usage are subject to change in future milestone releases.

7.1. Combined Global Filter and GatewayFilter Ordering

When a request matches a route, the filtering web handler adds all instances of GlobalFilter and all route-specific instances of GatewayFilter to a filter chain. This combined filter chain is sorted by the org.springframework.core.Ordered interface, which you can set by implementing the getOrder() method.
As Spring Cloud Gateway distinguishes between “pre” and “post” phases for filter logic execution (see How it Works), the filter with the highest precedence is the first in the “pre”-phase and the last in the “post”-phase.
The following listing configures a filter chain:
Example 55. ExampleConfiguration.java

  1. @Bean
  2. public GlobalFilter customFilter() {
  3. return new CustomGlobalFilter();
  4. }
  5. public class CustomGlobalFilter implements GlobalFilter, Ordered {
  6. @Override
  7. public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
  8. log.info("custom global filter");
  9. return chain.filter(exchange);
  10. }
  11. @Override
  12. public int getOrder() {
  13. return -1;
  14. }
  15. }

7.2. Forward Routing Filter

The ForwardRoutingFilter looks for a URI in the exchange attribute ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR. If the URL has a forward scheme (such as forward:///localendpoint), it uses the Spring DispatcherHandler to handle the request. The path part of the request URL is overridden with the path in the forward URL. The unmodified original URL is appended to the list in the ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR attribute.

7.3. The ReactiveLoadBalancerClientFilter

The ReactiveLoadBalancerClientFilter looks for a URI in the exchange attribute named ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR. If the URL has a lb scheme (such as lb://myservice), it uses the Spring Cloud ReactorLoadBalancer to resolve the name (myservice in this example) to an actual host and port and replaces the URI in the same attribute. The unmodified original URL is appended to the list in the ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR attribute. The filter also looks in the ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR attribute to see if it equals lb. If so, the same rules apply. The following listing configures a ReactiveLoadBalancerClientFilter:
Example 56. application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: myRoute
        uri: lb://service
        predicates:
        - Path=/service/**

By default, when a service instance cannot be found by the ReactorLoadBalancer, a 503 is returned. You can configure the gateway to return a 404 by setting spring.cloud.gateway.loadbalancer.use404=true. The isSecure value of the ServiceInstance returned from the ReactiveLoadBalancerClientFilter overrides the scheme specified in the request made to the Gateway. For example, if the request comes into the Gateway over HTTPS but the ServiceInstance indicates it is not secure, the downstream request is made over HTTP. The opposite situation can also apply. However, if GATEWAY_SCHEME_PREFIX_ATTR is specified for the route in the Gateway configuration, the prefix is stripped and the resulting scheme from the route URL overrides the ServiceInstance configuration. Gateway supports all the LoadBalancer features. You can read more about them in the Spring Cloud Commons documentation.

7.4. The Netty Routing Filter

The Netty routing filter runs if the URL located in the ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR exchange attribute has a http or https scheme. It uses the Netty HttpClient to make the downstream proxy request. The response is put in the ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR exchange attribute for use in a later filter. (There is also an experimental WebClientHttpRoutingFilter that performs the same function but does not require Netty.)

7.5. The Netty Write Response Filter

The NettyWriteResponseFilter runs if there is a Netty HttpClientResponse in the ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR exchange attribute. It runs after all other filters have completed and writes the proxy response back to the gateway client response. (There is also an experimental WebClientWriteResponseFilter that performs the same function but does not require Netty.)

7.6. The RouteToRequestUrl Filter

If there is a Route object in the ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR exchange attribute, the RouteToRequestUrlFilter runs. It creates a new URI, based off of the request URI but updated with the URI attribute of the Route object. The new URI is placed in the ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR exchange attribute.<br />If the URI has a scheme prefix, such aslb:ws://serviceid, thelbscheme is stripped from the URI and placed in theServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR` for use later in the filter chain.

7.7. The Websocket Routing Filter

I f the URL located in the ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR exchange attribute has a ws or wss scheme, the websocket routing filter runs. It uses the Spring WebSocket infrastructure to forward the websocket request downstream.
You can load-balance websockets by prefixing the URI with lb, such as lb:ws://serviceid.

If you use SockJS as a fallback over normal HTTP, you should configure a normal HTTP route as well as the websocket Route.

The following listing configures a websocket routing filter:
Example 57. application.yml

spring:
  cloud:
    gateway:
      routes:
      # SockJS route
      - id: websocket_sockjs_route
        uri: http://localhost:3001
        predicates:
        - Path=/websocket/info/**
      # Normal Websocket route
      - id: websocket_route
        uri: ws://localhost:3001
        predicates:
        - Path=/websocket/**

7.8. The Gateway Metrics Filter

To enable gateway metrics, add spring-boot-starter-actuator as a project dependency. Then, by default, the gateway metrics filter runs as long as the property spring.cloud.gateway.metrics.enabled is not set to false. This filter adds a timer metric named gateway.requests with the following tags:

  • routeId: The route ID.
  • routeUri: The URI to which the API is routed.
  • outcome: The outcome, as classified by HttpStatus.Series.
  • status: The HTTP status of the request returned to the client.
  • httpStatusCode: The HTTP Status of the request returned to the client.
  • httpMethod: The HTTP method used for the request.

These metrics are then available to be scraped from /actuator/metrics/gateway.requests and can be easily integrated with Prometheus to create a Grafana dashboard.

To enable the prometheus endpoint, add micrometer-registry-prometheus as a project dependency.

7.9. Marking An Exchange As Routed

After the gateway has routed a ServerWebExchange, it marks that exchange as “routed” by adding gatewayAlreadyRoutedto the exchange attributes. Once a request has been marked as routed, other routing filters will not route the request again, essentially skipping the filter. There are convenience methods that you can use to mark an exchange as routed or check if an exchange has already been routed.

  • ServerWebExchangeUtils.isAlreadyRouted takes a ServerWebExchange object and checks if it has been “routed”.
  • ServerWebExchangeUtils.setAlreadyRouted takes a ServerWebExchange object and marks it as “routed”.

    8. HttpHeadersFilters

    HttpHeadersFilters are applied to requests before sending them downstream, such as in the NettyRoutingFilter.

    8.1. Forwarded Headers Filter

    The Forwarded Headers Filter creates a Forwarded header to send to the downstream service. It adds the Host header, scheme and port of the current request to any existing Forwarded header.

    8.2. RemoveHopByHop Headers Filter

    The RemoveHopByHop Headers Filter removes headers from forwarded requests. The default list of headers that is removed comes from the IETF.
    The default removed headers are: Connection Keep-Alive Proxy-Authenticate Proxy-Authorization TE Trailer Transfer-Encoding Upgrade
    To change this, set the spring.cloud.gateway.filter.remove-hop-by-hop.headers property to the list of header names to remove.

    8.3. XForwarded Headers Filter

    The XForwarded Headers Filter creates various a X-Forwarded-* headers to send to the downstream service. It users the Host header, scheme, port and path of the current request to create the various headers.
    Creating of individual headers can be controlled by the following boolean properties (defaults to true):

  • spring.cloud.gateway.x-forwarded.for-enabled

  • spring.cloud.gateway.x-forwarded.host-enabled
  • spring.cloud.gateway.x-forwarded.port-enabled
  • spring.cloud.gateway.x-forwarded.proto-enabled
  • spring.cloud.gateway.x-forwarded.prefix-enabled

Appending multiple headers can be controlled by the following boolean properties (defaults to true):

  • spring.cloud.gateway.x-forwarded.for-append
  • spring.cloud.gateway.x-forwarded.host-append
  • spring.cloud.gateway.x-forwarded.port-append
  • spring.cloud.gateway.x-forwarded.proto-append
  • spring.cloud.gateway.x-forwarded.prefix-append

    9. TLS and SSL

    The gateway can listen for requests on HTTPS by following the usual Spring server configuration. The following example shows how to do so:
    Example 58. application.yml
    server:
    ssl:
      enabled: true
      key-alias: scg
      key-store-password: scg1234
      key-store: classpath:scg-keystore.p12
      key-store-type: PKCS12
    
    You can route gateway routes to both HTTP and HTTPS backends. If you are routing to an HTTPS backend, you can configure the gateway to trust all downstream certificates with the following configuration:
    Example 59. application.yml
    spring:
    cloud:
      gateway:
        httpclient:
          ssl:
            useInsecureTrustManager: true
    
    Using an insecure trust manager is not suitable for production. For a production deployment, you can configure the gateway with a set of known certificates that it can trust with the following configuration:
    Example 60. application.yml
    spring:
    cloud:
      gateway:
        httpclient:
          ssl:
            trustedX509Certificates:
            - cert1.pem
            - cert2.pem
    
    If the Spring Cloud Gateway is not provisioned with trusted certificates, the default trust store is used (which you can override by setting the javax.net.ssl.trustStore system property).

    9.1. TLS Handshake

    The gateway maintains a client pool that it uses to route to backends. When communicating over HTTPS, the client initiates a TLS handshake. A number of timeouts are associated with this handshake. You can configure these timeouts can be configured (defaults shown) as follows:
    Example 61. application.yml
    spring:
    cloud:
      gateway:
        httpclient:
          ssl:
            handshake-timeout-millis: 10000
            close-notify-flush-timeout-millis: 3000
            close-notify-read-timeout-millis: 0
    

    10. Configuration

    Configuration for Spring Cloud Gateway is driven by a collection of RouteDefinitionLocator instances. The following listing shows the definition of the RouteDefinitionLocator interface:
    Example 62. RouteDefinitionLocator.java
    public interface RouteDefinitionLocator {
      Flux<RouteDefinition> getRouteDefinitions();
    }
    
    By default, a PropertiesRouteDefinitionLocator loads properties by using Spring Boot’s @ConfigurationProperties mechanism.
    The earlier configuration examples all use a shortcut notation that uses positional arguments rather than named ones. The following two examples are equivalent:
    Example 63. application.yml
    \spring:
    cloud:
      gateway:
        routes:
        - id: setstatus_route
          uri: https://example.org
          filters:
          - name: SetStatus
            args:
              status: 401
        - id: setstatusshortcut_route
          uri: https://example.org
          filters:
          - SetStatus=401
    
    For some usages of the gateway, properties are adequate, but some production use cases benefit from loading configuration from an external source, such as a database. Future milestone versions will have RouteDefinitionLocator implementations based off of Spring Data Repositories, such as Redis, MongoDB, and Cassandra.

    11. Route Metadata Configuration

    You can configure additional parameters for each route by using metadata, as follows:
    Example 64. application.yml
    spring:
    cloud:
      gateway:
        routes:
        - id: route_with_metadata
          uri: https://example.org
          metadata:
            optionName: "OptionValue"
            compositeObject:
              name: "value"
            iAmNumber: 1
    
    You could acquire all metadata properties from an exchange, as follows:
    Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
    // get all metadata properties
    route.getMetadata();
    // get a single metadata property
    route.getMetadata(someKey);
    

    12. Http timeouts configuration

    Http timeouts (response and connect) can be configured for all routes and overridden for each specific route.

    12.1. Global timeouts

    To configure Global http timeouts:
    connect-timeout must be specified in milliseconds.
    response-timeout must be specified as a java.time.Duration
    global http timeouts example
    spring:
    cloud:
      gateway:
        httpclient:
          connect-timeout: 1000
          response-timeout: 5s
    

    12.2. Per-route timeouts

    To configure per-route timeouts:
    connect-timeout must be specified in milliseconds.
    response-timeout must be specified in milliseconds.
    per-route http timeouts configuration via configuration ```yaml
  • id: per_route_timeouts
      uri: https://example.org
      predicates:
        - name: Path
          args:
            pattern: /delay/{timeout}
      metadata:
        response-timeout: 200
        connect-timeout: 200
    
    per-route timeouts configuration using Java DSL
    ```java
    import static org.springframework.cloud.gateway.support.RouteMetadataUtils.CONNECT_TIMEOUT_ATTR;
    import static org.springframework.cloud.gateway.support.RouteMetadataUtils.RESPONSE_TIMEOUT_ATTR;
        @Bean
        public RouteLocator customRouteLocator(RouteLocatorBuilder routeBuilder){
           return routeBuilder.routes()
                 .route("test1", r -> {
                    return r.host("*.somehost.org").and().path("/somepath")
                          .filters(f -> f.addRequestHeader("header1", "header-value-1"))
                          .uri("http://someuri")
                          .metadata(RESPONSE_TIMEOUT_ATTR, 200)
                          .metadata(CONNECT_TIMEOUT_ATTR, 200);
                 })
                 .build();
        }
    

    12.3. Fluent Java Routes API

    To allow for simple configuration in Java, the RouteLocatorBuilder bean includes a fluent API. The following listing shows how it works:
    Example 65. GatewaySampleApplication.java
    // static imports from GatewayFilters and RoutePredicates
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder, ThrottleGatewayFilterFactory throttle) {
      return builder.routes()
              .route(r -> r.host("**.abc.org").and().path("/image/png")
                  .filters(f ->
                          f.addResponseHeader("X-TestHeader", "foobar"))
                  .uri("http://httpbin.org:80")
              )
              .route(r -> r.path("/image/webp")
                  .filters(f ->
                          f.addResponseHeader("X-AnotherHeader", "baz"))
                  .uri("http://httpbin.org:80")
                  .metadata("key", "value")
              )
              .route(r -> r.order(-1)
                  .host("**.throttle.org").and().path("/get")
                  .filters(f -> f.filter(throttle.apply(1,
                          1,
                          10,
                          TimeUnit.SECONDS)))
                  .uri("http://httpbin.org:80")
                  .metadata("key", "value")
              )
              .build();
    }
    
    This style also allows for more custom predicate assertions. The predicates defined by RouteDefinitionLocator beans are combined using logical and. By using the fluent Java API, you can use the and(), or(), and negate() operators on the Predicate class.

    12.4. The DiscoveryClient Route Definition Locator

    You can configure the gateway to create routes based on services registered with a DiscoveryClient compatible service registry.
    To enable this, set spring.cloud.gateway.discovery.locator.enabled=true and make sure a DiscoveryClient implementation (such as Netflix Eureka, Consul, or Zookeeper) is on the classpath and enabled.

    12.4.1. Configuring Predicates and Filters For DiscoveryClient Routes

    By default, the gateway defines a single predicate and filter for routes created with a DiscoveryClient.
    The default predicate is a path predicate defined with the pattern /serviceId/**, where serviceId is the ID of the service from the DiscoveryClient.
    The default filter is a rewrite path filter with the regex /serviceId/?(?<remaining>.*) and the replacement /${remaining}. This strips the service ID from the path before the request is sent downstream.
    If you want to customize the predicates or filters used by the DiscoveryClient routes, set spring.cloud.gateway.discovery.locator.predicates[x] and spring.cloud.gateway.discovery.locator.filters[y]. When doing so, you need to make sure to include the default predicate and filter shown earlier, if you want to retain that functionality. The following example shows what this looks like:
    Example 66. application.properties
    spring.cloud.gateway.discovery.locator.predicates[0].name: Path
    spring.cloud.gateway.discovery.locator.predicates[0].args[pattern]: "'/'+serviceId+'/**'"
    spring.cloud.gateway.discovery.locator.predicates[1].name: Host
    spring.cloud.gateway.discovery.locator.predicates[1].args[pattern]: "'**.foo.com'"
    spring.cloud.gateway.discovery.locator.filters[0].name: CircuitBreaker
    spring.cloud.gateway.discovery.locator.filters[0].args[name]: serviceId
    spring.cloud.gateway.discovery.locator.filters[1].name: RewritePath
    spring.cloud.gateway.discovery.locator.filters[1].args[regexp]: "'/' + serviceId + '/?(?<remaining>.*)'"
    spring.cloud.gateway.discovery.locator.filters[1].args[replacement]: "'/${remaining}'"
    

    13. Reactor Netty Access Logs

    To enable Reactor Netty access logs, set -Dreactor.netty.http.server.accessLogEnabled=true.

    It must be a Java System Property, not a Spring Boot property.

You can configure the logging system to have a separate access log file. The following example creates a Logback configuration:
Example 67. logback.xml

<appender name="accessLog" class="ch.qos.logback.core.FileAppender">
  <file>access_log.log</file>
  <encoder>
    <pattern>%msg%n</pattern>
  </encoder>
</appender>
<appender name="async" class="ch.qos.logback.classic.AsyncAppender">
  <appender-ref ref="accessLog" />
</appender>
<logger name="reactor.netty.http.server.AccessLog" level="INFO" additivity="false">
  <appender-ref ref="async"/>
</logger>

14. CORS Configuration

You can configure the gateway to control CORS behavior. The “global” CORS configuration is a map of URL patterns to Spring Framework CorsConfiguration. The following example configures CORS:
Example 68. application.yml

spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            allowedOrigins: "https://docs.spring.io"
            allowedMethods:
            - GET

In the preceding example, CORS requests are allowed from requests that originate from docs.spring.io for all GET requested paths.
To provide the same CORS configuration to requests that are not handled by some gateway route predicate, set the spring.cloud.gateway.globalcors.add-to-simple-url-handler-mapping property to true. This is useful when you try to support CORS preflight requests and your route predicate does not evalute to true because the HTTP method is options.

15. Actuator API

The /gateway actuator endpoint lets you monitor and interact with a Spring Cloud Gateway application. To be remotely accessible, the endpoint has to be enabled and exposed over HTTP or JMX in the application properties. The following listing shows how to do so:
Example 69. application.properties

management.endpoint.gateway.enabled=true # default value
management.endpoints.web.exposure.include=gateway

15.1. Verbose Actuator Format

A new, more verbose format has been added to Spring Cloud Gateway. It adds more detail to each route, letting you view the predicates and filters associated with each route along with any configuration that is available. The following example configures /actuator/gateway/routes:

[
  {
    "predicate": "(Hosts: [**.addrequestheader.org] && Paths: [/headers], match trailing slash: true)",
    "route_id": "add_request_header_test",
    "filters": [
      "[[AddResponseHeader X-Response-Default-Foo = 'Default-Bar'], order = 1]",
      "[[AddRequestHeader X-Request-Foo = 'Bar'], order = 1]",
      "[[PrefixPath prefix = '/httpbin'], order = 2]"
    ],
    "uri": "lb://testservice",
    "order": 0
  }
]

This feature is enabled by default. To disable it, set the following property:
Example 70. application.properties

spring.cloud.gateway.actuator.verbose.enabled=false

This will default to true in a future release.

15.2. Retrieving Route Filters

This section details how to retrieve route filters, including:

  • Global Filters
  • [gateway-route-filters]

    15.2.1. Global Filters

    To retrieve the global filters applied to all routes, make a GET request to /actuator/gateway/globalfilters. The resulting response is similar to the following:
    {
    "org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter@77856cc5": 10100,
    "org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter@4f6fd101": 10000,
    "org.springframework.cloud.gateway.filter.NettyWriteResponseFilter@32d22650": -1,
    "org.springframework.cloud.gateway.filter.ForwardRoutingFilter@106459d9": 2147483647,
    "org.springframework.cloud.gateway.filter.NettyRoutingFilter@1fbd5e0": 2147483647,
    "org.springframework.cloud.gateway.filter.ForwardPathFilter@33a71d23": 0,
    "org.springframework.cloud.gateway.filter.AdaptCachedBodyGlobalFilter@135064ea": 2147483637,
    "org.springframework.cloud.gateway.filter.WebsocketRoutingFilter@23c05889": 2147483646
    }
    
    The response contains the details of the global filters that are in place. For each global filter, there is a string representation of the filter object (for example, org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter@77856cc5) and the corresponding order in the filter chain.}

    15.2.2. Route Filters

    To retrieve the GatewayFilter factories applied to routes, make a GET request to /actuator/gateway/routefilters. The resulting response is similar to the following:
    {
    "[AddRequestHeaderGatewayFilterFactory@570ed9c configClass = AbstractNameValueGatewayFilterFactory.NameValueConfig]": null,
    "[SecureHeadersGatewayFilterFactory@fceab5d configClass = Object]": null,
    "[SaveSessionGatewayFilterFactory@4449b273 configClass = Object]": null
    }
    
    The response contains the details of the GatewayFilter factories applied to any particular route. For each factory there is a string representation of the corresponding object (for example, [SecureHeadersGatewayFilterFactory@fceab5d configClass = Object]). Note that the null value is due to an incomplete implementation of the endpoint controller, because it tries to set the order of the object in the filter chain, which does not apply to a GatewayFilter factory object.

    15.3. Refreshing the Route Cache

    To clear the routes cache, make a POST request to /actuator/gateway/refresh. The request returns a 200 without a response body.

    15.4. Retrieving the Routes Defined in the Gateway

    To retrieve the routes defined in the gateway, make a GET request to /actuator/gateway/routes. The resulting response is similar to the following:
    [{
    "route_id": "first_route",
    "route_object": {
      "predicate": "org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory$$Lambda$432/1736826640@1e9d7e7d",
      "filters": [
    "OrderedGatewayFilter{delegate=org.springframework.cloud.gateway.filter.factory.PreserveHostHeaderGatewayFilterFactory$$Lambda$436/674480275@6631ef72, order=0}"
      ]
    },
    "order": 0
    },
    {
    "route_id": "second_route",
    "route_object": {
      "predicate": "org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory$$Lambda$432/1736826640@cd8d298",
      "filters": []
    },
    "order": 0
    }]
    
    The response contains the details of all the routes defined in the gateway. The following table describes the structure of each element (each is a route) of the response:
Path Type Description
route_id String The route ID.
route_object.predicate Object The route predicate.
route_object.filters Array The GatewayFilter factories applied to the route.
order Number The route order.

15.5. Retrieving Information about a Particular Route

To retrieve information about a single route, make a GET request to /actuator/gateway/routes/{id} (for example, /actuator/gateway/routes/first_route). The resulting response is similar to the following:

[{
  "id": "first_route",
  "predicates": [{
    "name": "Path",
    "args": {"_genkey_0":"/first"}
  }],
  "filters": [],
  "uri": "https://www.uri-destination.org",
  "order": 0
}]

The following table describes the structure of the response:

Path Type Description
id String The route ID.
predicates Array The collection of route predicates. Each item defines the name and the arguments of a given predicate.
filters Array The collection of filters applied to the route.
uri String The destination URI of the route.
order Number The route order.

15.6. Creating and Deleting a Particular Route

To create a route, make a POST request to /gateway/routes/{id_route_to_create} with a JSON body that specifies the fields of the route (see Retrieving Information about a Particular Route).
To delete a route, make a DELETE request to /gateway/routes/{id_route_to_delete}.

15.7. Recap: The List of All endpoints

The folloiwng table below summarizes the Spring Cloud Gateway actuator endpoints (note that each endpoint has /actuator/gateway as the base-path):

ID HTTP Method Description
globalfilters GET Displays the list of global filters applied to the routes.
routefilters GET Displays the list of GatewayFilter factories applied to a particular route.
refresh POST Clears the routes cache.
routes GET Displays the list of routes defined in the gateway.
routes/{id} GET Displays information about a particular route.
routes/{id} POST Adds a new route to the gateway.
routes/{id} DELETE Removes an existing route from the gateway.

16. Troubleshooting

This section covers common problems that may arise when you use Spring Cloud Gateway.

16.1. Log Levels

The following loggers may contain valuable troubleshooting information at the DEBUG and TRACE levels:

  • org.springframework.cloud.gateway
  • org.springframework.http.server.reactive
  • org.springframework.web.reactive
  • org.springframework.boot.autoconfigure.web
  • reactor.netty
  • redisratelimiter

    16.2. Wiretap

    The Reactor Netty HttpClient and HttpServer can have wiretap enabled. When combined with setting the reactor.netty log level to DEBUG or TRACE, it enables the logging of information, such as headers and bodies sent and received across the wire. To enable wiretap, set spring.cloud.gateway.httpserver.wiretap=true or spring.cloud.gateway.httpclient.wiretap=true for the HttpServer and HttpClient, respectively.

    17. Developer Guide

    These are basic guides to writing some custom components of the gateway.

    17.1. Writing Custom Route Predicate Factories

    In order to write a Route Predicate you will need to implement RoutePredicateFactory. There is an abstract class called AbstractRoutePredicateFactory which you can extend.
    MyRoutePredicateFactory.java
    public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<HeaderRoutePredicateFactory.Config> {
      public MyRoutePredicateFactory() {
          super(Config.class);
      }
      @Override
      public Predicate<ServerWebExchange> apply(Config config) {
          // grab configuration from Config object
          return exchange -> {
              //grab the request
              ServerHttpRequest request = exchange.getRequest();
              //take information from the request to see if it
              //matches configuration.
              return matches(config, request);
          };
      }
      public static class Config {
          //Put the configuration properties for your filter here
      }
    }
    

    17.2. Writing Custom GatewayFilter Factories

    To write a GatewayFilter, you must implement GatewayFilterFactory. You can extend an abstract class called AbstractGatewayFilterFactory. The following examples show how to do so:
    Example 71. PreGatewayFilterFactory.java
    public class PreGatewayFilterFactory extends AbstractGatewayFilterFactory<PreGatewayFilterFactory.Config> {
      public PreGatewayFilterFactory() {
          super(Config.class);
      }
      @Override
      public GatewayFilter apply(Config config) {
          // grab configuration from Config object
          return (exchange, chain) -> {
              //If you want to build a "pre" filter you need to manipulate the
              //request before calling chain.filter
              ServerHttpRequest.Builder builder = exchange.getRequest().mutate();
              //use builder to manipulate the request
              return chain.filter(exchange.mutate().request(builder.build()).build());
          };
      }
      public static class Config {
          //Put the configuration properties for your filter here
      }
    }
    
    PostGatewayFilterFactory.java
    public class PostGatewayFilterFactory extends AbstractGatewayFilterFactory<PostGatewayFilterFactory.Config> {
      public PostGatewayFilterFactory() {
          super(Config.class);
      }
      @Override
      public GatewayFilter apply(Config config) {
          // grab configuration from Config object
          return (exchange, chain) -> {
              return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                  ServerHttpResponse response = exchange.getResponse();
                  //Manipulate the response in some way
              }));
          };
      }
      public static class Config {
          //Put the configuration properties for your filter here
      }
    }
    

    17.2.1. Naming Custom Filters And References In Configuration

    Custom filters class names should end in GatewayFilterFactory.
    For example, to reference a filter named Something in configuration files, the filter must be in a class named SomethingGatewayFilterFactory.

    It is possible to create a gateway filter named without theGatewayFilterFactory suffix, such as class AnotherThing. This filter could be referenced as AnotherThing in configuration files. This is not a supported naming convention and this syntax may be removed in future releases. Please update the filter name to be compliant.

17.3. Writing Custom Global Filters

To write a custom global filter, you must implement GlobalFilter interface. This applies the filter to all requests.
The following examples show how to set up global pre and post filters, respectively:

@Bean
public GlobalFilter customGlobalFilter() {
    return (exchange, chain) -> exchange.getPrincipal()
        .map(Principal::getName)
        .defaultIfEmpty("Default User")
        .map(userName -> {
          //adds header to proxied request
          exchange.getRequest().mutate().header("CUSTOM-REQUEST-HEADER", userName).build();
          return exchange;
        })
        .flatMap(chain::filter);
}
@Bean
public GlobalFilter customGlobalPostFilter() {
    return (exchange, chain) -> chain.filter(exchange)
        .then(Mono.just(exchange))
        .map(serverWebExchange -> {
          //adds header to response
          serverWebExchange.getResponse().getHeaders().set("CUSTOM-RESPONSE-HEADER",
              HttpStatus.OK.equals(serverWebExchange.getResponse().getStatusCode()) ? "It worked": "It did not work");
          return serverWebExchange;
        })
        .then();
}

18. Building a Simple Gateway by Using Spring MVC or Webflux

The following describes an alternative style gateway. None of the prior documentation applies to what follows.

Spring Cloud Gateway provides a utility object called ProxyExchange. You can use it inside a regular Spring web handler as a method parameter. It supports basic downstream HTTP exchanges through methods that mirror the HTTP verbs. With MVC, it also supports forwarding to a local handler through the forward() method. To use the ProxyExchange, include the right module in your classpath (either spring-cloud-gateway-mvc or spring-cloud-gateway-webflux).
The following MVC example proxies a request to /test downstream to a remote server:

@RestController
@SpringBootApplication
public class GatewaySampleApplication {
    @Value("${remote.home}")
    private URI home;
    @GetMapping("/test")
    public ResponseEntity<?> proxy(ProxyExchange<byte[]> proxy) throws Exception {
        return proxy.uri(home.toString() + "/image/png").get();
    }
}

The following example does the same thing with Webflux:

@RestController
@SpringBootApplication
public class GatewaySampleApplication {
    @Value("${remote.home}")
    private URI home;
    @GetMapping("/test")
    public Mono<ResponseEntity<?>> proxy(ProxyExchange<byte[]> proxy) throws Exception {
        return proxy.uri(home.toString() + "/image/png").get();
    }
}

Convenience methods on the ProxyExchange enable the handler method to discover and enhance the URI path of the incoming request. For example, you might want to extract the trailing elements of a path to pass them downstream:

@GetMapping("/proxy/path/**")
public ResponseEntity<?> proxyPath(ProxyExchange<byte[]> proxy) throws Exception {
  String path = proxy.path("/proxy/path/");
  return proxy.uri(home.toString() + "/foos/" + path).get();
}

All the features of Spring MVC and Webflux are available to gateway handler methods. As a result, you can inject request headers and query parameters, for instance, and you can constrain the incoming requests with declarations in the mapping annotation. See the documentation for @RequestMapping in Spring MVC for more details of those features.
You can add headers to the downstream response by using the header() methods on ProxyExchange.
You can also manipulate response headers (and anything else you like in the response) by adding a mapper to the get() method (and other methods). The mapper is a Function that takes the incoming ResponseEntity and converts it to an outgoing one.
First-class support is provided for “sensitive” headers (by default, cookie and authorization), which are not passed downstream, and for “proxy” (x-forwarded-*) headers.

19. Configuration properties

To see the list of all Spring Cloud Gateway related configuration properties, see the appendix.