- 7. Global Filters
- 7.1. Combined Global Filter and
GatewayFilter
Ordering - 7.2. Forward Routing Filter
- 7.3. The
ReactiveLoadBalancerClientFilter
- 7.4. The Netty Routing Filter
- 7.5. The Netty Write Response Filter
- 7.6. The
RouteToRequestUrl
Filter - 7.7. The Websocket Routing Filter
- 7.8. The Gateway Metrics Filter
- 7.9. Marking An Exchange As Routed
- 7.1. Combined Global Filter and
- 8. HttpHeadersFilters
- 9. TLS and SSL
- 10. Configuration
- 11. Route Metadata Configuration
- 12. Http timeouts configuration
- 13. Reactor Netty Access Logs
- 14. CORS Configuration
- 15. Actuator API
- 16. Troubleshooting
- 17. Developer Guide
- 18. Building a Simple Gateway by Using Spring MVC or Webflux
- 19. Configuration properties
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
@Bean
public GlobalFilter customFilter() {
return new CustomGlobalFilter();
}
public class CustomGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("custom global filter");
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -1;
}
}
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
, a503
is returned. You can configure the gateway to return a404
by settingspring.cloud.gateway.loadbalancer.use404=true
. TheisSecure
value of theServiceInstance
returned from theReactiveLoadBalancerClientFilter
overrides the scheme specified in the request made to the Gateway. For example, if the request comes into the Gateway overHTTPS
but theServiceInstance
indicates it is not secure, the downstream request is made overHTTP
. The opposite situation can also apply. However, ifGATEWAY_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 theServiceInstance
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 as
lb:ws://serviceid, the
lbscheme is stripped from the URI and placed in the
ServerWebExchangeUtils.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 gatewayAlreadyRouted
to 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 aServerWebExchange
object and checks if it has been “routed”.ServerWebExchangeUtils.setAlreadyRouted
takes aServerWebExchange
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 aForwarded
header to send to the downstream service. It adds theHost
header, scheme and port of the current request to any existingForwarded
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 thespring.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 aX-Forwarded-*
headers to send to the downstream service. It users theHost
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
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:server: ssl: enabled: true key-alias: scg key-store-password: scg1234 key-store: classpath:scg-keystore.p12 key-store-type: PKCS12
Example 59. application.yml
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:spring: cloud: gateway: httpclient: ssl: useInsecureTrustManager: true
Example 60. application.yml
If the Spring Cloud Gateway is not provisioned with trusted certificates, the default trust store is used (which you can override by setting thespring: cloud: gateway: httpclient: ssl: trustedX509Certificates: - cert1.pem - cert2.pem
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.ymlspring: 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 ofRouteDefinitionLocator
instances. The following listing shows the definition of theRouteDefinitionLocator
interface:
Example 62. RouteDefinitionLocator.java
By default, apublic interface RouteDefinitionLocator { Flux<RouteDefinition> getRouteDefinitions(); }
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
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\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
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
You could acquire all metadata properties from an exchange, as follows:spring: cloud: gateway: routes: - id: route_with_metadata uri: https://example.org metadata: optionName: "OptionValue" compositeObject: name: "value" iAmNumber: 1
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 examplespring: 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, theRouteLocatorBuilder
bean includes a fluent API. The following listing shows how it works:
Example 65. GatewaySampleApplication.java
This style also allows for more custom predicate assertions. The predicates defined by// 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(); }
RouteDefinitionLocator
beans are combined using logicaland
. By using the fluent Java API, you can use theand()
,or()
, andnegate()
operators on thePredicate
class.12.4. The
You can configure the gateway to create routes based on services registered with aDiscoveryClient
Route Definition LocatorDiscoveryClient
compatible service registry.
To enable this, setspring.cloud.gateway.discovery.locator.enabled=true
and make sure aDiscoveryClient
implementation (such as Netflix Eureka, Consul, or Zookeeper) is on the classpath and enabled.12.4.1. Configuring Predicates and Filters For
By default, the gateway defines a single predicate and filter for routes created with aDiscoveryClient
RoutesDiscoveryClient
.
The default predicate is a path predicate defined with the pattern/serviceId/**
, whereserviceId
is the ID of the service from theDiscoveryClient
.
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 theDiscoveryClient
routes, setspring.cloud.gateway.discovery.locator.predicates[x]
andspring.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.propertiesspring.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 aGET
request to/actuator/gateway/globalfilters
. The resulting response is similar to the following:
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": 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 }
org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter@77856cc5
) and the corresponding order in the filter chain.}15.2.2. Route Filters
To retrieve theGatewayFilter
factories applied to routes, make aGET
request to/actuator/gateway/routefilters
. The resulting response is similar to the following:
The response contains the details of the{ "[AddRequestHeaderGatewayFilterFactory@570ed9c configClass = AbstractNameValueGatewayFilterFactory.NameValueConfig]": null, "[SecureHeadersGatewayFilterFactory@fceab5d configClass = Object]": null, "[SaveSessionGatewayFilterFactory@4449b273 configClass = Object]": null }
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 thenull
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 aGatewayFilter
factory object.15.3. Refreshing the Route Cache
To clear the routes cache, make aPOST
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 aGET
request to/actuator/gateway/routes
. The resulting response is similar to the following:
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:[{ "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 }]
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 NettyHttpClient
andHttpServer
can have wiretap enabled. When combined with setting thereactor.netty
log level toDEBUG
orTRACE
, it enables the logging of information, such as headers and bodies sent and received across the wire. To enable wiretap, setspring.cloud.gateway.httpserver.wiretap=true
orspring.cloud.gateway.httpclient.wiretap=true
for theHttpServer
andHttpClient
, 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 implementRoutePredicateFactory
. There is an abstract class calledAbstractRoutePredicateFactory
which you can extend.
MyRoutePredicateFactory.javapublic 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 aGatewayFilter
, you must implementGatewayFilterFactory
. You can extend an abstract class calledAbstractGatewayFilterFactory
. The following examples show how to do so:
Example 71. PreGatewayFilterFactory.javapublic 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 inGatewayFilterFactory
.
For example, to reference a filter namedSomething
in configuration files, the filter must be in a class namedSomethingGatewayFilterFactory
.It is possible to create a gateway filter named without the
GatewayFilterFactory
suffix, such asclass AnotherThing
. This filter could be referenced asAnotherThing
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.