From 0cc2d48a15801f82941d6fbab1e32476e200554b Mon Sep 17 00:00:00 2001 From: sgibb Date: Mon, 11 Sep 2023 16:12:19 -0400 Subject: [PATCH] Split files --- .../ROOT/pages/spring-cloud-gateway.adoc | 3436 ----------------- .../spring-cloud-gateway/actuator-api.adoc | 307 ++ .../aot-and-native-image-support.adoc | 7 + ...ding-a-simple-by-using-mvc-or-webflux.adoc | 78 + .../configuration-properties.adoc | 4 + .../spring-cloud-gateway/configuration.adoc | 49 + ...dicate-factories-and-filter-factories.adoc | 50 + .../cors-configuration.adoc | 65 + .../spring-cloud-gateway/developer-guide.adoc | 158 + .../fluent-java-routes-api.adoc | 43 + .../gatewayfilter-factories.adoc | 9 + .../circuitbreaker-filter-factory.adoc | 182 + .../default-filters.adoc | 20 + .../fallback-headers.adoc | 45 + .../local-cache-response-filter.adoc | 57 + ...ovejsonattributesresponsebody-factory.adoc | 46 + .../the-addrequestheader-factory.adoc | 44 + ...addrequestheadersifnotpresent-factory.adoc | 48 + .../the-addrequestparameter-factory.adoc | 44 + .../the-addresponseheader-factory.adoc | 45 + .../the-cacherequestbody-factory.adoc | 46 + .../the-deduperesponseheader-factory.adoc | 27 + .../the-jsontogrpc-factory.adoc | 80 + .../the-maprequestheader-factory.adoc | 26 + .../the-modifyrequestbody-factory.adoc | 46 + .../the-modifyresponsebody-factory.adoc | 26 + .../the-prefixpath-factory.adoc | 24 + .../the-preservehostheader-factory.adoc | 22 + .../the-redirectto-factory.adoc | 28 + .../the-removerequestheader-factory.adoc | 24 + .../the-removerequestparameter-factory.adoc | 25 + .../the-removeresponseheader-factory.adoc | 28 + .../the-requestheadersize-factory.adoc | 24 + .../the-requestratelimiter-factory.adoc | 130 + .../the-requestsize-factory.adoc | 39 + .../the-retry-factory.adoc | 90 + ...rewritelocationresponseheader-factory.adoc | 37 + .../the-rewritepath-factory.adoc | 26 + .../the-rewriteresponseheader-factory.adoc | 25 + .../the-savesession-factory.adoc | 26 + .../the-secureheaders-factory.adoc | 40 + .../the-setpath-factory.adoc | 28 + .../the-setrequestheader-factory.adoc | 45 + .../the-setrequesthostheader-factory.adoc | 29 + .../the-setresponseheader-factory.adoc | 45 + .../the-setstatus-factory.adoc | 44 + .../the-stripprefix-factory.adoc | 26 + .../the-tokenrelay-factory.adoc | 103 + .../spring-cloud-gateway/global-filters.adoc | 206 + .../pages/spring-cloud-gateway/glossary.adoc | 10 + .../spring-cloud-gateway/how-it-works.adoc | 14 + .../http-timeouts-configuration.adoc | 75 + .../httpheadersfilters.adoc | 45 + .../reactor-netty-access-logs.adoc | 29 + .../request-predicates-factories.adoc | 406 ++ .../route-metadata-configuration.adoc | 36 + .../pages/spring-cloud-gateway/starter.adoc | 15 + ...coveryclient-route-definition-locator.adoc | 38 + .../spring-cloud-gateway/tls-and-ssl.adoc | 79 + .../spring-cloud-gateway/troubleshooting.adoc | 24 + 60 files changed, 3437 insertions(+), 3436 deletions(-) create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/actuator-api.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/aot-and-native-image-support.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/building-a-simple-by-using-mvc-or-webflux.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/configuration-properties.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/configuration.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/configuring-route-predicate-factories-and-filter-factories.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/cors-configuration.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/developer-guide.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/fluent-java-routes-api.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/circuitbreaker-filter-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/default-filters.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/fallback-headers.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/local-cache-response-filter.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/removejsonattributesresponsebody-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-addrequestheader-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-addrequestheadersifnotpresent-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-addrequestparameter-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-addresponseheader-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-cacherequestbody-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-deduperesponseheader-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-jsontogrpc-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-maprequestheader-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-modifyrequestbody-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-modifyresponsebody-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-prefixpath-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-preservehostheader-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-redirectto-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-removerequestheader-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-removerequestparameter-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-removeresponseheader-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-requestheadersize-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-requestratelimiter-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-requestsize-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-retry-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-rewritelocationresponseheader-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-rewritepath-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-rewriteresponseheader-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-savesession-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-secureheaders-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-setpath-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-setrequestheader-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-setrequesthostheader-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-setresponseheader-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-setstatus-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-stripprefix-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-tokenrelay-factory.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/global-filters.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/glossary.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/how-it-works.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/http-timeouts-configuration.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/httpheadersfilters.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/reactor-netty-access-logs.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/request-predicates-factories.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/route-metadata-configuration.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/starter.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/the-discoveryclient-route-definition-locator.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/tls-and-ssl.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway/troubleshooting.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway.adoc index 62a0c56c..d2680fe4 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway.adoc @@ -6,3439 +6,3 @@ include::_attributes.adoc[] include::intro.adoc[] -[[gateway-starter]] -== How to Include Spring Cloud Gateway - -To include Spring Cloud Gateway in your project, use the starter with a group ID of `org.springframework.cloud` and an artifact ID of `spring-cloud-starter-gateway`. -See the https://projects.spring.io/spring-cloud/[Spring Cloud Project page] for details on setting up your build system with the current Spring Cloud Release Train. - -If you include the starter, but you do not want the gateway to be enabled, set `spring.cloud.gateway.enabled=false`. - -IMPORTANT: Spring Cloud Gateway is built on https://spring.io/projects/spring-boot#learn[Spring Boot], https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html[Spring WebFlux], and https://projectreactor.io/docs[Project Reactor]. -As a consequence, many of the familiar synchronous libraries (Spring Data and Spring Security, for example) and patterns you know may not apply when you use Spring Cloud Gateway. -If you are unfamiliar with these projects, we suggest you begin by reading their documentation to familiarize yourself with some new concepts before working with Spring Cloud Gateway. - -IMPORTANT: Spring Cloud Gateway requires the Netty runtime provided by Spring Boot and Spring Webflux. -It does not work in a traditional Servlet Container or when built as a WAR. - -[[glossary]] -== Glossary - -* *Route*: The basic building block of the gateway. -It is defined by an ID, a destination URI, a collection of predicates, and a collection of filters. A route is matched if the aggregate predicate is true. -* *Predicate*: This is a https://docs.oracle.com/javase/8/docs/api/java/util/function/Predicate.html[Java 8 Function Predicate]. The input type is a https://docs.spring.io/spring/docs/5.0.x/javadoc-api/org/springframework/web/server/ServerWebExchange.html[Spring Framework `ServerWebExchange`]. -This lets you match on anything from the HTTP request, such as headers or parameters. -* *Filter*: These are instances of {github-code}/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/GatewayFilter.java[`GatewayFilter`] that have been constructed with a specific factory. -Here, you can modify requests and responses before or after sending the downstream request. - -[[gateway-how-it-works]] -== How It Works - -The following diagram provides a high-level overview of how Spring Cloud Gateway works: - -image::spring_cloud_gateway_diagram.png[Spring Cloud Gateway Diagram] - -Clients make requests to Spring Cloud Gateway. If the Gateway Handler Mapping determines that a request matches a route, it is sent to the Gateway Web Handler. -This handler runs the request through a filter chain that is specific to the request. -The reason the filters are divided by the dotted line is that filters can run logic both before and after the proxy request is sent. -All "`pre`" filter logic is executed. Then the proxy request is made. After the proxy request is made, the "`post`" filter logic is run. - -NOTE: URIs defined in routes without a port get default port values of 80 and 443 for the HTTP and HTTPS URIs, respectively. - -[[configuring-route-predicate-factories-and-gateway-filter-factories]] -== Configuring Route Predicate Factories and Gateway Filter Factories - -There are two ways to configure predicates and filters: shortcuts and fully expanded arguments. Most examples below use the shortcut way. - -The name and argument names are listed as `code` in the first sentence or two of each section. The arguments are typically listed in the order that are needed for the shortcut configuration. - -[[shortcut-configuration]] -=== Shortcut Configuration - -Shortcut configuration is recognized by the filter name, followed by an equals sign (`=`), followed by argument values separated by commas (`,`). - -.application.yml -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: after_route - uri: https://example.org - predicates: - - Cookie=mycookie,mycookievalue ----- - -The previous sample defines the `Cookie` Route Predicate Factory with two arguments, the cookie name, `mycookie` and the value to match `mycookievalue`. - -[[fully-expanded-arguments]] -=== Fully Expanded Arguments - -Fully expanded arguments appear more like standard yaml configuration with name/value pairs. Typically, there will be a `name` key and an `args` key. The `args` key is a map of key value pairs to configure the predicate or filter. - -.application.yml -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: after_route - uri: https://example.org - predicates: - - name: Cookie - args: - name: mycookie - regexp: mycookievalue ----- - -This is the full configuration of the shortcut configuration of the `Cookie` predicate shown above. - -[[gateway-request-predicates-factories]] -== Route Predicate Factories - -Spring Cloud Gateway matches routes as part of the Spring WebFlux `HandlerMapping` infrastructure. -Spring Cloud Gateway includes many built-in route predicate factories. -All of these predicates match on different attributes of the HTTP request. -You can combine multiple route predicate factories with logical `and` statements. - -[[the-after-route-predicate-factory]] -=== The After Route Predicate Factory - -The `After` route predicate factory takes one parameter, a `datetime` (which is a java `ZonedDateTime`). -This predicate matches requests that happen after the specified datetime. -The following example configures an after route predicate: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: after_route - uri: https://example.org - predicates: - - After=2017-01-20T17:42:47.789-07:00[America/Denver] ----- -==== - -This route matches any request made after Jan 20, 2017 17:42 Mountain Time (Denver). - -[[the-before-route-predicate-factory]] -=== The Before Route Predicate Factory - -The `Before` route predicate factory takes one parameter, a `datetime` (which is a java `ZonedDateTime`). -This predicate matches requests that happen before the specified `datetime`. -The following example configures a before route predicate: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: before_route - uri: https://example.org - predicates: - - Before=2017-01-20T17:42:47.789-07:00[America/Denver] ----- -==== - -This route matches any request made before Jan 20, 2017 17:42 Mountain Time (Denver). - -[[the-between-route-predicate-factory]] -=== The Between Route Predicate Factory - -The `Between` route predicate factory takes two parameters, `datetime1` and `datetime2` -which are java `ZonedDateTime` objects. -This predicate matches requests that happen after `datetime1` and before `datetime2`. -The `datetime2` parameter must be after `datetime1`. -The following example configures a between route predicate: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: between_route - uri: https://example.org - predicates: - - Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver] ----- -==== - -This route matches any request made after Jan 20, 2017 17:42 Mountain Time (Denver) and before Jan 21, 2017 17:42 Mountain Time (Denver). -This could be useful for maintenance windows. - -[[the-cookie-route-predicate-factory]] -=== The Cookie Route Predicate Factory - -The `Cookie` route predicate factory takes two parameters, the cookie `name` and a `regexp` (which is a Java regular expression). -This predicate matches cookies that have the given name and whose values match the regular expression. -The following example configures a cookie route predicate factory: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: cookie_route - uri: https://example.org - predicates: - - Cookie=chocolate, ch.p ----- -==== - -This route matches requests that have a cookie named `chocolate` whose value matches the `ch.p` regular expression. - -[[the-header-route-predicate-factory]] -=== The Header Route Predicate Factory - -The `Header` route predicate factory takes two parameters, the `header` and a `regexp` (which is a Java regular expression). -This predicate matches with a header that has the given name whose value matches the regular expression. -The following example configures a header route predicate: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: header_route - uri: https://example.org - predicates: - - Header=X-Request-Id, \d+ ----- -==== - -This route matches if the request has a header named `X-Request-Id` whose value matches the `\d+` regular expression (that is, it has a value of one or more digits). - -[[the-host-route-predicate-factory]] -=== The Host Route Predicate Factory - -The `Host` route predicate factory takes one parameter: a list of host name `patterns`. -The pattern is an Ant-style pattern with `.` as the separator. -This predicates matches the `Host` header that matches the pattern. -The following example configures a host route predicate: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: host_route - uri: https://example.org - predicates: - - Host=**.somehost.org,**.anotherhost.org ----- -==== - -URI template variables (such as `{sub}.myhost.org`) are supported as well. - -This route matches if the request has a `Host` header with a value of `www.somehost.org` or `beta.somehost.org` or `www.anotherhost.org`. - -This predicate extracts the URI template variables (such as `sub`, defined in the preceding example) as a map of names and values and places it in the `ServerWebExchange.getAttributes()` with a key defined in `ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE`. -Those values are then available for use by <> - - -[[the-method-route-predicate-factory]] -=== The Method Route Predicate Factory - -The `Method` Route Predicate Factory takes a `methods` argument which is one or more parameters: the HTTP methods to match. -The following example configures a method route predicate: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: method_route - uri: https://example.org - predicates: - - Method=GET,POST ----- -==== - -This route matches if the request method was a `GET` or a `POST`. - -[[the-path-route-predicate-factory]] -=== The Path Route Predicate Factory - -The `Path` Route Predicate Factory takes two parameters: a list of Spring `PathMatcher` `patterns` and an optional flag called `matchTrailingSlash` (defaults to `true`). -The following example configures a path route predicate: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: path_route - uri: https://example.org - predicates: - - Path=/red/{segment},/blue/{segment} ----- -==== - -This route matches if the request path was, for example: `/red/1` or `/red/1/` or `/red/blue` or `/blue/green`. - -If `matchTrailingSlash` is set to `false`, then request path `/red/1/` will not be matched. - -This predicate extracts the URI template variables (such as `segment`, defined in the preceding example) as a map of names and values and places it in the `ServerWebExchange.getAttributes()` with a key defined in `ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE`. -Those values are then available for use by <> - -A utility method (called `get`) is available to make access to these variables easier. -The following example shows how to use the `get` method: - -==== -[source,java] ----- -Map uriVariables = ServerWebExchangeUtils.getUriTemplateVariables(exchange); - -String segment = uriVariables.get("segment"); ----- -==== - -[[the-query-route-predicate-factory]] -=== The Query Route Predicate Factory - -The `Query` route predicate factory takes two parameters: a required `param` and an optional `regexp` (which is a Java regular expression). -The following example configures a query route predicate: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: query_route - uri: https://example.org - predicates: - - Query=green ----- -==== - -The preceding route matches if the request contained a `green` query parameter. - -.application.yml -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: query_route - uri: https://example.org - predicates: - - Query=red, gree. ----- - -The preceding route matches if the request contained a `red` query parameter whose value matched the `gree.` regexp, so `green` and `greet` would match. - - -[[the-remoteaddr-route-predicate-factory]] -=== The RemoteAddr Route Predicate Factory - -The `RemoteAddr` route predicate factory takes a list (min size 1) of `sources`, which are CIDR-notation (IPv4 or IPv6) strings, such as `192.168.0.1/16` (where `192.168.0.1` is an IP address and `16` is a subnet mask). -The following example configures a RemoteAddr route predicate: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: remoteaddr_route - uri: https://example.org - predicates: - - RemoteAddr=192.168.1.1/24 ----- -==== - -This route matches if the remote address of the request was, for example, `192.168.1.10`. - -[[modifying-the-way-remote-addresses-are-resolved]] -==== Modifying the Way Remote Addresses Are Resolved - -By default, the RemoteAddr route predicate factory uses the remote address from the incoming request. -This may not match the actual client IP address if Spring Cloud Gateway sits behind a proxy layer. - -You can customize the way that the remote address is resolved by setting a custom `RemoteAddressResolver`. -Spring Cloud Gateway comes with one non-default remote address resolver that is based off of the https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For[X-Forwarded-For header], `XForwardedRemoteAddressResolver`. - -`XForwardedRemoteAddressResolver` has two static constructor methods, which take different approaches to security: - -* `XForwardedRemoteAddressResolver::trustAll` returns a `RemoteAddressResolver` that always takes the first IP address found in the `X-Forwarded-For` header. -This approach is vulnerable to spoofing, as a malicious client could set an initial value for the `X-Forwarded-For`, which would be accepted by the resolver. - -* `XForwardedRemoteAddressResolver::maxTrustedIndex` takes an index that correlates to the number of trusted infrastructure running in front of Spring Cloud Gateway. -If Spring Cloud Gateway is, for example only accessible through HAProxy, then a value of 1 should be used. -If two hops of trusted infrastructure are required before Spring Cloud Gateway is accessible, then a value of 2 should be used. - -Consider the following header value: - -==== -[source] ----- -X-Forwarded-For: 0.0.0.1, 0.0.0.2, 0.0.0.3 ----- -==== - -The following `maxTrustedIndex` values yield the following remote addresses: - -[options="header"] -|=== -|`maxTrustedIndex` | result -|[`Integer.MIN_VALUE`,0] | (invalid, `IllegalArgumentException` during initialization) -|1 | 0.0.0.3 -|2 | 0.0.0.2 -|3 | 0.0.0.1 -|[4, `Integer.MAX_VALUE`] | 0.0.0.1 -|=== -[[gateway-route-filters]] - -The following example shows how to achieve the same configuration with Java: - -.GatewayConfig.java -==== -[source,java] ----- -RemoteAddressResolver resolver = XForwardedRemoteAddressResolver - .maxTrustedIndex(1); - -... - -.route("direct-route", - r -> r.remoteAddr("10.1.1.1", "10.10.1.1/24") - .uri("https://downstream1") -.route("proxied-route", - r -> r.remoteAddr(resolver, "10.10.1.1", "10.10.1.1/24") - .uri("https://downstream2") -) ----- -==== - -[[the-weight-route-predicate-factory]] -=== The Weight Route Predicate Factory - -The `Weight` route predicate factory takes two arguments: `group` and `weight` (an int). The weights are calculated per group. -The following example configures a weight route predicate: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: weight_high - uri: https://weighthigh.org - predicates: - - Weight=group1, 8 - - id: weight_low - uri: https://weightlow.org - predicates: - - Weight=group1, 2 ----- -==== - -This route would forward ~80% of traffic to https://weighthigh.org and ~20% of traffic to https://weighlow.org - -[[the-xforwarded-remote-addr-route-predicate-factory]] -=== The XForwarded Remote Addr Route Predicate Factory - -The `XForwarded Remote Addr` route predicate factory takes a list (min size 1) of `sources`, which are CIDR-notation (IPv4 or IPv6) strings, such as `192.168.0.1/16` (where `192.168.0.1` is an IP address and `16` is a subnet mask). - -This route predicate allows requests to be filtered based on the `X-Forwarded-For` HTTP header. - -This can be used with reverse proxies such as load balancers or web application firewalls where -the request should only be allowed if it comes from a trusted list of IP addresses used by those -reverse proxies. - - -The following example configures a XForwardedRemoteAddr route predicate: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: xforwarded_remoteaddr_route - uri: https://example.org - predicates: - - XForwardedRemoteAddr=192.168.1.1/24 ----- -==== - -This route matches if the `X-Forwarded-For` header contains, for example, `192.168.1.10`. - -[[gatewayfilter-factories]] -== `GatewayFilter` Factories - -Route filters allow the modification of the incoming HTTP request or outgoing HTTP response in some manner. -Route filters are scoped to a particular route. -Spring Cloud Gateway includes many built-in GatewayFilter Factories. - -NOTE: For more detailed examples of how to use any of the following filters, take a look at the https://github.com/spring-cloud/spring-cloud-gateway/tree/master/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory[unit tests]. - -[[the-addrequestheader-gatewayfilter-factory]] -=== The `AddRequestHeader` `GatewayFilter` Factory - -The `AddRequestHeader` `GatewayFilter` factory takes a `name` and `value` parameter. -The following example configures an `AddRequestHeader` `GatewayFilter`: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: add_request_header_route - uri: https://example.org - filters: - - AddRequestHeader=X-Request-red, blue ----- -==== - -This listing adds `X-Request-red:blue` header to the downstream request's headers for all matching requests. - -`AddRequestHeader` is aware of the URI variables used to match a path or host. -URI variables may be used in the value and are expanded at runtime. -The following example configures an `AddRequestHeader` `GatewayFilter` that uses a variable: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: add_request_header_route - uri: https://example.org - predicates: - - Path=/red/{segment} - filters: - - AddRequestHeader=X-Request-Red, Blue-{segment} ----- -==== - -[[the-addrequestheadersifnotpresent-gatewayfilter-factory]] -=== The `AddRequestHeadersIfNotPresent` `GatewayFilter` Factory - -The `AddRequestHeadersIfNotPresent` `GatewayFilter` factory takes a collection of `name` and `value` pairs separated by colon. -The following example configures an `AddRequestHeadersIfNotPresent` `GatewayFilter`: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: add_request_headers_route - uri: https://example.org - filters: - - AddRequestHeadersIfNotPresent=X-Request-Color-1:blue,X-Request-Color-2:green ----- -==== - -This listing adds 2 headers `X-Request-Color-1:blue` and `X-Request-Color-2:green` to the downstream request's headers for all matching requests. -This is similar to how `AddRequestHeader` works, but unlike `AddRequestHeader` it will do it only if the header is not already there. -Otherwise, the original value in the client request is sent. - -Additionally, to set a multi-valued header, use the header name multiple times like `AddRequestHeadersIfNotPresent=X-Request-Color-1:blue,X-Request-Color-1:green`. - -`AddRequestHeadersIfNotPresent` also supports URI variables used to match a path or host. -URI variables may be used in the value and are expanded at runtime. -The following example configures an `AddRequestHeadersIfNotPresent` `GatewayFilter` that uses a variable: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: add_request_header_route - uri: https://example.org - predicates: - - Path=/red/{segment} - filters: - - AddRequestHeadersIfNotPresent=X-Request-Red:Blue-{segment} ----- -==== - -[[the-addrequestparameter-gatewayfilter-factory]] -=== The `AddRequestParameter` `GatewayFilter` Factory - -The `AddRequestParameter` `GatewayFilter` Factory takes a `name` and `value` parameter. -The following example configures an `AddRequestParameter` `GatewayFilter`: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: add_request_parameter_route - uri: https://example.org - filters: - - AddRequestParameter=red, blue ----- -==== - -This will add `red=blue` to the downstream request's query string for all matching requests. - -`AddRequestParameter` is aware of the URI variables used to match a path or host. -URI variables may be used in the value and are expanded at runtime. -The following example configures an `AddRequestParameter` `GatewayFilter` that uses a variable: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: add_request_parameter_route - uri: https://example.org - predicates: - - Host: {segment}.myhost.org - filters: - - AddRequestParameter=foo, bar-{segment} ----- -==== - -[[the-addresponseheader-gatewayfilter-factory]] -=== The `AddResponseHeader` `GatewayFilter` Factory - -The `AddResponseHeader` `GatewayFilter` Factory takes a `name` and `value` parameter. -The following example configures an `AddResponseHeader` `GatewayFilter`: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: add_response_header_route - uri: https://example.org - filters: - - AddResponseHeader=X-Response-Red, Blue ----- -==== - -This adds `X-Response-Red:Blue` header to the downstream response's headers for all matching requests. - -`AddResponseHeader` is aware of URI variables used to match a path or host. -URI variables may be used in the value and are expanded at runtime. -The following example configures an `AddResponseHeader` `GatewayFilter` that uses a variable: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: add_response_header_route - uri: https://example.org - predicates: - - Host: {segment}.myhost.org - filters: - - AddResponseHeader=foo, bar-{segment} ----- -==== - - -[[spring-cloud-circuitbreaker-filter-factory]] -=== The `CircuitBreaker` `GatewayFilter` Factory - -The Spring Cloud CircuitBreaker GatewayFilter factory uses the Spring Cloud CircuitBreaker APIs to wrap Gateway routes in -a circuit breaker. Spring Cloud CircuitBreaker supports multiple libraries that can be used with Spring Cloud Gateway. Spring Cloud supports Resilience4J out of the box. - -To enable the Spring Cloud CircuitBreaker filter, you need to place `spring-cloud-starter-circuitbreaker-reactor-resilience4j` on the classpath. -The following example configures a Spring Cloud CircuitBreaker `GatewayFilter`: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: circuitbreaker_route - uri: https://example.org - filters: - - CircuitBreaker=myCircuitBreaker ----- -==== - -To configure the circuit breaker, see the configuration for the underlying circuit breaker implementation you are using. - -* https://cloud.spring.io/spring-cloud-circuitbreaker/reference/html/spring-cloud-circuitbreaker.html[Resilience4J Documentation] - -The Spring Cloud CircuitBreaker filter can also accept an optional `fallbackUri` parameter. -Currently, only `forward:` schemed URIs are supported. -If the fallback is called, the request is forwarded to the controller matched by the URI. -The following example configures such a fallback: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: circuitbreaker_route - uri: lb://backing-service:8088 - predicates: - - Path=/consumingServiceEndpoint - filters: - - name: CircuitBreaker - args: - name: myCircuitBreaker - fallbackUri: forward:/inCaseOfFailureUseThis - - RewritePath=/consumingServiceEndpoint, /backingServiceEndpoint ----- -==== - -The following listing does the same thing in Java: - -.Application.java -==== -[source,java] ----- -@Bean -public RouteLocator routes(RouteLocatorBuilder builder) { - return builder.routes() - .route("circuitbreaker_route", r -> r.path("/consumingServiceEndpoint") - .filters(f -> f.circuitBreaker(c -> c.name("myCircuitBreaker").fallbackUri("forward:/inCaseOfFailureUseThis")) - .rewritePath("/consumingServiceEndpoint", "/backingServiceEndpoint")).uri("lb://backing-service:8088") - .build(); -} ----- -==== - -This example forwards to the `/inCaseofFailureUseThis` URI when the circuit breaker fallback is called. -Note that this example also demonstrates the (optional) Spring Cloud LoadBalancer load-balancing (defined by the `lb` prefix on the destination URI). - -CircuitBreaker also supports URI variables in the `fallbackUri`. -This allows more complex routing options, like forwarding sections of the original host or url path using https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/util/pattern/PathPattern.html[PathPattern expression]. - -In the example below the call `consumingServiceEndpoint/users/1` will be redirected to `inCaseOfFailureUseThis/users/1`. - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: circuitbreaker_route - uri: lb://backing-service:8088 - predicates: - - Path=/consumingServiceEndpoint/{*segments} - filters: - - name: CircuitBreaker - args: - name: myCircuitBreaker - fallbackUri: forward:/inCaseOfFailureUseThis/{segments} ----- -==== - -The primary scenario is to use the `fallbackUri` to define an internal controller or handler within the gateway application. -However, you can also reroute the request to a controller or handler in an external application, as follows: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: ingredients - uri: lb://ingredients - predicates: - - Path=//ingredients/** - filters: - - name: CircuitBreaker - args: - name: fetchIngredients - fallbackUri: forward:/fallback - - id: ingredients-fallback - uri: http://localhost:9994 - predicates: - - Path=/fallback ----- -==== - -In this example, there is no `fallback` endpoint or handler in the gateway application. -However, there is one in another application, registered under `http://localhost:9994`. - -In case of the request being forwarded to fallback, the Spring Cloud CircuitBreaker Gateway filter also provides the `Throwable` that has caused it. -It is added to the `ServerWebExchange` as the `ServerWebExchangeUtils.CIRCUITBREAKER_EXECUTION_EXCEPTION_ATTR` attribute that can be used when handling the fallback within the gateway application. - -For the external controller/handler scenario, headers can be added with exception details. -You can find more information on doing so in the <>. - -[[circuit-breaker-status-codes]] -==== Tripping The Circuit Breaker On Status Codes - -In some cases you might want to trip a circuit breaker based on the status code -returned from the route it wraps. The circuit breaker config object takes a list of -status codes that if returned will cause the circuit breaker to be tripped. When setting the -status codes you want to trip the circuit breaker you can either use an integer with the status code -value or the String representation of the `HttpStatus` enumeration. - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: circuitbreaker_route - uri: lb://backing-service:8088 - predicates: - - Path=/consumingServiceEndpoint - filters: - - name: CircuitBreaker - args: - name: myCircuitBreaker - fallbackUri: forward:/inCaseOfFailureUseThis - statusCodes: - - 500 - - "NOT_FOUND" ----- -==== - -.Application.java -==== -[source,java] ----- -@Bean -public RouteLocator routes(RouteLocatorBuilder builder) { - return builder.routes() - .route("circuitbreaker_route", r -> r.path("/consumingServiceEndpoint") - .filters(f -> f.circuitBreaker(c -> c.name("myCircuitBreaker").fallbackUri("forward:/inCaseOfFailureUseThis").addStatusCode("INTERNAL_SERVER_ERROR")) - .rewritePath("/consumingServiceEndpoint", "/backingServiceEndpoint")).uri("lb://backing-service:8088") - .build(); -} ----- -==== - -[[the-cacherequestbody-gatewayfilter-factory]] -=== The `CacheRequestBody` `GatewayFilter` Factory -Some situations necessitate reading the request body. Since the request can be read only once, we need to cache the request body. -You can use the `CacheRequestBody` filter to cache the request body before sending it downstream and getting the body from `exchange` attribute. - -The following listing shows how to cache the request body `GatewayFilter`: - -==== -[source,java] ----- -@Bean -public RouteLocator routes(RouteLocatorBuilder builder) { - return builder.routes() - .route("cache_request_body_route", r -> r.path("/downstream/**") - .filters(f -> f.prefixPath("/httpbin") - .cacheRequestBody(String.class).uri(uri)) - .build(); -} ----- -==== - - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: cache_request_body_route - uri: lb://downstream - predicates: - - Path=/downstream/** - filters: - - name: CacheRequestBody - args: - bodyClass: java.lang.String ----- -==== -`CacheRequestBody` extracts the request body and converts it to a body class (such as `java.lang.String`, defined in the preceding example). -`CacheRequestBody` then places it in the attributes available from `ServerWebExchange.getAttributes()`, with a key defined in `ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR`. - -NOTE: This filter works only with HTTP (including HTTPS) requests. - -[[the-deduperesponseheader-gatewayfilter-factory]] -=== The `DedupeResponseHeader` `GatewayFilter` Factory - -The `DedupeResponseHeader` GatewayFilter factory takes a `name` parameter and an optional `strategy` parameter. `name` can contain a space-separated list of header names. -The following example configures a `DedupeResponseHeader` `GatewayFilter`: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: dedupe_response_header_route - uri: https://example.org - filters: - - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin ----- -==== - -This removes duplicate values of `Access-Control-Allow-Credentials` and `Access-Control-Allow-Origin` response headers in cases when both the gateway CORS logic and the downstream logic add them. - -The `DedupeResponseHeader` filter also accepts an optional `strategy` parameter. -The accepted values are `RETAIN_FIRST` (default), `RETAIN_LAST`, and `RETAIN_UNIQUE`. - - -[[fallback-headers]] -=== The `FallbackHeaders` `GatewayFilter` Factory - -The `FallbackHeaders` factory lets you add Spring Cloud CircuitBreaker execution exception details in the headers of a request forwarded to a `fallbackUri` in an external application, as in the following scenario: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: ingredients - uri: lb://ingredients - predicates: - - Path=//ingredients/** - filters: - - name: CircuitBreaker - args: - name: fetchIngredients - fallbackUri: forward:/fallback - - id: ingredients-fallback - uri: http://localhost:9994 - predicates: - - Path=/fallback - filters: - - name: FallbackHeaders - args: - executionExceptionTypeHeaderName: Test-Header ----- -==== - -In this example, after an execution exception occurs while running the circuit breaker, the request is forwarded to the `fallback` endpoint or handler in an application running on `localhost:9994`. -The headers with the exception type, message and (if available) root cause exception type and message are added to that request by the `FallbackHeaders` filter. - -You can overwrite the names of the headers in the configuration by setting the values of the following arguments (shown with their default values): - -* `executionExceptionTypeHeaderName` (`"Execution-Exception-Type"`) -* `executionExceptionMessageHeaderName` (`"Execution-Exception-Message"`) -* `rootCauseExceptionTypeHeaderName` (`"Root-Cause-Exception-Type"`) -* `rootCauseExceptionMessageHeaderName` (`"Root-Cause-Exception-Message"`) - -For more information on circuit breakers and the gateway see the <>. - -[[the-jsontogrpc-gatewayfilter-factory]] -=== The `JsonToGrpc` `GatewayFilter` Factory - -The JSONToGRPCFilter GatewayFilter Factory converts a JSON payload to a gRPC request. - -The filter takes the following arguments: - -* `protoDescriptor`: Proto descriptor file. - -This file can be generated using `protoc` and specifying the `--descriptor_set_out` flag: - -[source,bash] ----- -protoc --proto_path=src/main/resources/proto/ \ ---descriptor_set_out=src/main/resources/proto/hello.pb \ -src/main/resources/proto/hello.proto ----- - -* `protoFile`: Proto definition file. - -* `service`: Short name of the service that handles the request. - -* `method`: Method name in the service that handles the request. - -NOTE: `streaming` is not supported. - - -*application.yml.* - -[source,java] ----- -@Bean -public RouteLocator routes(RouteLocatorBuilder builder) { - return builder.routes() - .route("json-grpc", r -> r.path("/json/hello").filters(f -> { - String protoDescriptor = "file:src/main/proto/hello.pb"; - String protoFile = "file:src/main/proto/hello.proto"; - String service = "HelloService"; - String method = "hello"; - return f.jsonToGRPC(protoDescriptor, protoFile, service, method); - }).uri(uri)) ----- - -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: json-grpc - uri: https://localhost:6565/testhello - predicates: - - Path=/json/** - filters: - - name: JsonToGrpc - args: - protoDescriptor: file:proto/hello.pb - protoFile: file:proto/hello.proto - service: HelloService - method: hello - ----- - -When a request is made through the gateway to `/json/hello`, the request is transformed by using the definition provided in `hello.proto`, sent to `HelloService/hello`, and the response back is transformed to JSON. - -By default, it creates a `NettyChannel` by using the default `TrustManagerFactory`. However, you can customize this `TrustManager` by creating a bean of type `GrpcSslConfigurer`: - -[source,java] ----- - -@Configuration -public class GRPCLocalConfiguration { - @Bean - public GRPCSSLContext sslContext() { - TrustManager trustManager = trustAllCerts(); - return new GRPCSSLContext(trustManager); - } -} ----- - -[[local-cache-response-filter]] -=== The `LocalResponseCache` `GatewayFilter` Factory - -This filter allows caching the response body and headers to follow these rules: - -* It can only cache bodiless GET requests. -* It caches the response only for one of the following status codes: HTTP 200 (OK), HTTP 206 (Partial Content), or HTTP 301 (Moved Permanently). -* Response data is not cached if `Cache-Control` header does not allow it (`no-store` present in the request or `no-store` or `private` present in the response). -* If the response is already cached and a new request is performed with no-cache value in `Cache-Control` header, it returns a bodiless response with 304 (Not Modified). - -This filter configures the local response cache per route and is available only if the `spring.cloud.gateway.filter.local-response-cache.enabled` property is enabled. And a <> is also available as feature. - -It accepts the first parameter to override the time to expire a cache entry (expressed in `s` for seconds, `m` for minutes, and `h` for hours) and a second parameter to set the maximum size of the cache to evict entries for this route (`KB`, `MB`, or `GB`). - -The following listing shows how to add local response cache `GatewayFilter`: - -==== -[source,java] ----- -@Bean -public RouteLocator routes(RouteLocatorBuilder builder) { - return builder.routes() - .route("rewrite_response_upper", r -> r.host("*.rewriteresponseupper.org") - .filters(f -> f.prefixPath("/httpbin") - .localResponseCache(Duration.ofMinutes(30), "500MB") - ).uri(uri)) - .build(); -} ----- - -or this - -.application.yaml -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: resource - uri: http://localhost:9000 - predicates: - - Path=/resource - filters: - - LocalResponseCache=30m,500MB ----- -==== - -NOTE: This filter also automatically calculates the `max-age` value in the HTTP `Cache-Control` header. -Only if `max-age` is present on the original response is the value rewritten with the number of seconds set in the `timeToLive` configuration parameter. -In consecutive calls, this value is recalculated with the number of seconds left until the response expires. - -NOTE: To enable this feature, add `com.github.ben-manes.caffeine:caffeine` and `spring-boot-starter-cache` as project dependencies. - -WARNING: If your project creates custom `CacheManager` beans, it will either need to be marked with `@Primary` or injected using `@Qualifier`. - - -[[the-maprequestheader-gatewayfilter-factory]] -=== The `MapRequestHeader` `GatewayFilter` Factory - -The `MapRequestHeader` `GatewayFilter` factory takes `fromHeader` and `toHeader` parameters. -It creates a new named header (`toHeader`), and the value is extracted out of an existing named header (`fromHeader`) from the incoming http request. -If the input header does not exist, the filter has no impact. -If the new named header already exists, its values are augmented with the new values. -The following example configures a `MapRequestHeader`: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: map_request_header_route - uri: https://example.org - filters: - - MapRequestHeader=Blue, X-Request-Red ----- -==== - -This adds the `X-Request-Red:` header to the downstream request with updated values from the incoming HTTP request's `Blue` header. - -[[the-modifyrequestbody-gatewayfilter-factory]] -=== The `ModifyRequestBody` `GatewayFilter` Factory - -You can use the `ModifyRequestBody` filter to modify the request body before it is sent downstream by the gateway. - -NOTE: This filter can be configured only by using the Java DSL. - -The following listing shows how to modify a request body `GatewayFilter`: - -==== -[source,java] ----- -@Bean -public RouteLocator routes(RouteLocatorBuilder builder) { - return builder.routes() - .route("rewrite_request_obj", r -> r.host("*.rewriterequestobj.org") - .filters(f -> f.prefixPath("/httpbin") - .modifyRequestBody(String.class, Hello.class, MediaType.APPLICATION_JSON_VALUE, - (exchange, s) -> Mono.just(new Hello(s.toUpperCase())))).uri(uri)) - .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; - } -} ----- - -NOTE: If the request has no body, the `RewriteFilter` is passed `null`. `Mono.empty()` should be returned to assign a missing body in the request. - -==== - - -[[the-modifyresponsebody-gatewayfilter-factory]] -=== The `ModifyResponseBody` `GatewayFilter` Factory - -You can use the `ModifyResponseBody` filter to modify the response body before it is sent back to the client. - -NOTE: This filter can be configured only by using the Java DSL. - -The following listing shows how to modify a response body `GatewayFilter`: - -==== -[source,java] ----- -@Bean -public RouteLocator routes(RouteLocatorBuilder builder) { - return builder.routes() - .route("rewrite_response_upper", r -> r.host("*.rewriteresponseupper.org") - .filters(f -> f.prefixPath("/httpbin") - .modifyResponseBody(String.class, String.class, - (exchange, s) -> Mono.just(s.toUpperCase()))).uri(uri)) - .build(); -} ----- - -NOTE: If the response has no body, the `RewriteFilter` is passed `null`. `Mono.empty()` should be returned to assign a missing body in the response. -==== - -[[the-prefixpath-gatewayfilter-factory]] -=== The `PrefixPath` `GatewayFilter` Factory - -The `PrefixPath` `GatewayFilter` factory takes a single `prefix` parameter. -The following example configures a `PrefixPath` `GatewayFilter`: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: prefixpath_route - uri: https://example.org - filters: - - PrefixPath=/mypath ----- -==== - -This prefixes `/mypath` to the path of all matching requests. -So a request to `/hello` is sent to `/mypath/hello`. - -[[the-preservehostheader-gatewayfilter-factory]] -=== The `PreserveHostHeader` `GatewayFilter` Factory - -The `PreserveHostHeader` `GatewayFilter` factory has no parameters. -This filter sets a request attribute that the routing filter inspects to determine if the original host header should be sent rather than the host header determined by the HTTP client. -The following example configures a `PreserveHostHeader` `GatewayFilter`: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: preserve_host_route - uri: https://example.org - filters: - - PreserveHostHeader ----- -==== - -[[the-redirectto-gatewayfilter-factory]] -=== The `RedirectTo` `GatewayFilter` Factory - -The `RedirectTo` `GatewayFilter` factory takes two parameters, `status` and `url`. -The `status` parameter should be a 300 series redirect HTTP code, such as 301. -The `url` parameter should be a valid URL. -This is the value of the `Location` header. -For relative redirects, you should use `uri: no://op` as the uri of your route definition. -The following listing configures a `RedirectTo` `GatewayFilter`: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: prefixpath_route - uri: https://example.org - filters: - - RedirectTo=302, https://acme.org ----- -==== - -This will send a status 302 with a `Location:https://acme.org` header to perform a redirect. - - -[[removejsonattributesresponsebody-gatewayfilter-factory]] -=== `RemoveJsonAttributesResponseBody` `GatewayFilter` Factory - -The `RemoveJsonAttributesResponseBody` `GatewayFilter` factory takes a collection of `attribute names` to search for, an optional last parameter from the list can be a boolean to remove the attributes just at root level (that's the default value if not present at the end of the parameter configuration, `false`) or recursively (`true`). -It provides a convenient method to apply a transformation to JSON body content by deleting attributes from it. - -The following example configures an `RemoveJsonAttributesResponseBody` `GatewayFilter`: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: removejsonattributes_route - uri: https://example.org - filters: - - RemoveJsonAttributesResponseBody=id,color ----- -==== - -This removes attributes "id" and "color" from the JSON content body at root level. - -The following example configures an `RemoveJsonAttributesResponseBody` `GatewayFilter` that uses the optional last parameter: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: removejsonattributes_recursively_route - uri: https://example.org - predicates: - - Path=/red/{segment} - filters: - - RemoveJsonAttributesResponseBody=id,color,true ----- -==== - -This removes attributes "id" and "color" from the JSON content body at any level. - -[[the-removerequestheader-gatewayfilter-factory]] -=== The `RemoveRequestHeader` GatewayFilter Factory - -The `RemoveRequestHeader` `GatewayFilter` factory takes a `name` parameter. -It is the name of the header to be removed. -The following listing configures a `RemoveRequestHeader` `GatewayFilter`: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: removerequestheader_route - uri: https://example.org - filters: - - RemoveRequestHeader=X-Request-Foo ----- -==== - -This removes the `X-Request-Foo` header before it is sent downstream. - -[[the-removerequestparameter-gatewayfilter-factory]] -=== The `RemoveRequestParameter` `GatewayFilter` Factory - -The `RemoveRequestParameter` `GatewayFilter` factory takes a `name` parameter. -It is the name of the query parameter to be removed. -The following example configures a `RemoveRequestParameter` `GatewayFilter`: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: removerequestparameter_route - uri: https://example.org - filters: - - RemoveRequestParameter=red ----- -==== - -This will remove the `red` parameter before it is sent downstream. - - -[[the-removeresponseheader-gatewayfilter-factory]] -=== The `RemoveResponseHeader` `GatewayFilter` Factory - -The `RemoveResponseHeader` `GatewayFilter` factory takes a `name` parameter. -It is the name of the header to be removed. -The following listing configures a `RemoveResponseHeader` `GatewayFilter`: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: removeresponseheader_route - uri: https://example.org - filters: - - RemoveResponseHeader=X-Response-Foo ----- -==== - -This will remove the `X-Response-Foo` header from the response before it is returned to the gateway client. - -To remove any kind of sensitive header, you should configure this filter for any routes for which you may want to do so. -In addition, you can configure this filter once by using `spring.cloud.gateway.default-filters` and have it applied to all routes. - - -[[the-requestheadersize-gatewayfilter-factory]] -=== The `RequestHeaderSize` `GatewayFilter` Factory - -The `RequestHeaderSize` `GatewayFilter` factory takes `maxSize` and `errorHeaderName` parameters. -The `maxSize` parameter is the maximum data size allowed by the request header (including key and value). The `errorHeaderName` parameter sets the name of the response header containing an error message, by default it is "errorMessage". -The following listing configures a `RequestHeaderSize` `GatewayFilter`: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: requestheadersize_route - uri: https://example.org - filters: - - RequestHeaderSize=1000B ----- -==== - -This will send a status 431 if size of any request header is greater than 1000 Bytes. - -[[the-requestratelimiter-gatewayfilter-factory]] -=== The `RequestRateLimiter` `GatewayFilter` Factory - -The `RequestRateLimiter` `GatewayFilter` factory uses a `RateLimiter` implementation to determine if the current request is allowed to proceed. If it is not, a status of `HTTP 429 - Too Many Requests` (by default) is returned. - -This filter takes an optional `keyResolver` parameter and parameters specific to the rate limiter (described <>). - -`keyResolver` is a bean that implements the `KeyResolver` interface. -In configuration, reference the bean by name using SpEL. -`#{@myKeyResolver}` is a SpEL expression that references a bean named `myKeyResolver`. -The following listing shows the `KeyResolver` interface: - -.KeyResolver.java -==== -[source,java] ----- -public interface KeyResolver { - Mono resolve(ServerWebExchange exchange); -} ----- -==== - -[[key-resolver-section]] -The `KeyResolver` interface lets pluggable strategies derive the key for limiting requests. -In future milestone releases, there will be some `KeyResolver` implementations. - -The default implementation of `KeyResolver` is the `PrincipalNameKeyResolver`, which retrieves the `Principal` from the `ServerWebExchange` and calls `Principal.getName()`. - -By default, if the `KeyResolver` does not find a key, requests are denied. -You can adjust this behavior by setting the `spring.cloud.gateway.filter.request-rate-limiter.deny-empty-key` (`true` or `false`) and `spring.cloud.gateway.filter.request-rate-limiter.empty-key-status-code` properties. - -[NOTE] -===== -The `RequestRateLimiter` is not configurable with the "shortcut" notation. The following example below is _invalid_: - -.application.properties -==== ----- -# INVALID SHORTCUT CONFIGURATION -spring.cloud.gateway.routes[0].filters[0]=RequestRateLimiter=2, 2, #{@userkeyresolver} ----- -==== -===== - -[[the-redis-ratelimiter]] -==== The Redis `RateLimiter` - -The Redis implementation is based on work done at https://stripe.com/blog/rate-limiters[Stripe]. -It requires the use of the `spring-boot-starter-data-redis-reactive` Spring Boot starter. - -The algorithm used is the https://en.wikipedia.org/wiki/Token_bucket[Token Bucket Algorithm]. - -The `redis-rate-limiter.replenishRate` property defines how many requests per second to allow (without any dropped requests). -This is the rate at which the token bucket is filled. - -The `redis-rate-limiter.burstCapacity` property is the maximum number of requests a user is allowed in a single second (without any dropped requests). -This is the number of tokens the token bucket can hold. -Setting this value to zero blocks all requests. - -The `redis-rate-limiter.requestedTokens` property is how many tokens a request costs. -This is the number of tokens taken from the bucket for each request and defaults to `1`. - -A steady rate is accomplished by setting the same value in `replenishRate` and `burstCapacity`. -Temporary bursts can be allowed by setting `burstCapacity` higher than `replenishRate`. -In this case, the rate limiter needs to be allowed some time between bursts (according to `replenishRate`), as two consecutive bursts results in dropped requests (`HTTP 429 - Too Many Requests`). -The following listing configures a `redis-rate-limiter`: - -Rate limits below `1 request/s` are accomplished by setting `replenishRate` to the wanted number of requests, `requestedTokens` to the timespan in seconds, and `burstCapacity` to the product of `replenishRate` and `requestedTokens`. -For example, setting `replenishRate=1`, `requestedTokens=60`, and `burstCapacity=60` results in a limit of `1 request/min`. -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: requestratelimiter_route - uri: https://example.org - filters: - - name: RequestRateLimiter - args: - redis-rate-limiter.replenishRate: 10 - redis-rate-limiter.burstCapacity: 20 - redis-rate-limiter.requestedTokens: 1 - ----- -==== - -The following example configures a `KeyResolver` in Java: - -.Config.java -==== -[source,java] ----- -@Bean -KeyResolver userKeyResolver() { - return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user")); -} ----- -==== - -This defines a request rate limit of 10 per user. A burst of 20 is allowed, but, in the next second, only 10 requests are available. -The `KeyResolver` is a simple one that gets the `user` request parameter -NOTE: This is not recommended for production - -You can also define a rate limiter as a bean that implements the `RateLimiter` interface. -In configuration, you can reference the bean by name using SpEL. -`#{@myRateLimiter}` is a SpEL expression that references a bean with named `myRateLimiter`. -The following listing defines a rate limiter that uses the `KeyResolver` defined in the previous listing: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: requestratelimiter_route - uri: https://example.org - filters: - - name: RequestRateLimiter - args: - rate-limiter: "#{@myRateLimiter}" - key-resolver: "#{@userKeyResolver}" - ----- -==== - -[[the-rewritelocationresponseheader-gatewayfilter-factory]] -=== The `RewriteLocationResponseHeader` `GatewayFilter` Factory - -The `RewriteLocationResponseHeader` `GatewayFilter` factory modifies the value of the `Location` response header, usually to get rid of backend-specific details. -It takes the `stripVersionMode`, `locationHeaderName`, `hostValue`, and `protocolsRegex` parameters. -The following listing configures a `RewriteLocationResponseHeader` `GatewayFilter`: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: rewritelocationresponseheader_route - uri: http://example.org - filters: - - RewriteLocationResponseHeader=AS_IN_REQUEST, Location, , ----- -==== - -For example, for a request of `POST https://api.example.com/some/object/name`, the `Location` response header value of `https://object-service.prod.example.net/v2/some/object/id` is rewritten as `https://api.example.com/some/object/id`. - -The `stripVersionMode` parameter has the following possible values: `NEVER_STRIP`, `AS_IN_REQUEST` (default), and `ALWAYS_STRIP`. - -* `NEVER_STRIP`: The version is not stripped, even if the original request path contains no version. -* `AS_IN_REQUEST`: The version is stripped only if the original request path contains no version. -* `ALWAYS_STRIP`: The version is always stripped, even if the original request path contains version. - -The `hostValue` parameter, if provided, is used to replace the `host:port` portion of the response `Location` header. -If it is not provided, the value of the `Host` request header is used. - -The `protocolsRegex` parameter must be a valid regex `String`, against which the protocol name is matched. -If it is not matched, the filter does nothing. -The default is `http|https|ftp|ftps`. - -[[the-rewritepath-gatewayfilter-factory]] -=== The `RewritePath` `GatewayFilter` Factory - -The `RewritePath` `GatewayFilter` factory takes a path `regexp` parameter and a `replacement` parameter. -This uses Java regular expressions for a flexible way to rewrite the request path. -The following listing configures a `RewritePath` `GatewayFilter`: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: rewritepath_route - uri: https://example.org - predicates: - - Path=/red/** - filters: - - RewritePath=/red/?(?.*), /$\{segment} ----- -==== - -For a request path of `/red/blue`, this sets the path to `/blue` before making the downstream request. Note that the `$` should be replaced with `$\` because of the YAML specification. - -[[the-rewriteresponseheader-gatewayfilter-factory]] -=== The `RewriteResponseHeader` `GatewayFilter` Factory - -The `RewriteResponseHeader` `GatewayFilter` factory takes `name`, `regexp`, and `replacement` parameters. -It uses Java regular expressions for a flexible way to rewrite the response header value. -The following example configures a `RewriteResponseHeader` `GatewayFilter`: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: rewriteresponseheader_route - uri: https://example.org - filters: - - RewriteResponseHeader=X-Response-Red, , password=[^&]+, password=*** ----- -==== - -For a header value of `/42?user=ford&password=omg!what&flag=true`, it is set to `/42?user=ford&password=\***&flag=true` after making the downstream request. -You must use `$\` to mean `$` because of the YAML specification. - -[[the-savesession-gatewayfilter-factory]] -=== The `SaveSession` `GatewayFilter` Factory - -The `SaveSession` `GatewayFilter` factory forces a `WebSession::save` operation _before_ forwarding the call downstream. -This is of particular use when using something like https://projects.spring.io/spring-session/[Spring Session] with a lazy data store, and you need to ensure the session state has been saved before making the forwarded call. -The following example configures a `SaveSession` `GatewayFilter`: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: save_session - uri: https://example.org - predicates: - - Path=/foo/** - filters: - - SaveSession ----- -==== - -If you integrate https://projects.spring.io/spring-security/[Spring Security] with Spring Session and want to ensure security details have been forwarded to the remote process, this is critical. - -[[the-secureheaders-gatewayfilter-factory]] -=== The `SecureHeaders` `GatewayFilter` Factory - -The `SecureHeaders` `GatewayFilter` factory adds a number of headers to the response, per the recommendation made in https://blog.appcanary.com/2017/http-security-headers.html[this blog post]. - -The following headers (shown with their default values) are added: - -* `X-Xss-Protection:1 (mode=block`) -* `Strict-Transport-Security (max-age=631138519`) -* `X-Frame-Options (DENY)` -* `X-Content-Type-Options (nosniff)` -* `Referrer-Policy (no-referrer)` -* `Content-Security-Policy (default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src https:; style-src 'self' https: 'unsafe-inline)'` -* `X-Download-Options (noopen)` -* `X-Permitted-Cross-Domain-Policies (none)` - -To change the default values, set the appropriate property in the `spring.cloud.gateway.filter.secure-headers` namespace. -The following properties are available: - -* `xss-protection-header` -* `strict-transport-security` -* `frame-options` -* `content-type-options` -* `referrer-policy` -* `content-security-policy` -* `download-options` -* `permitted-cross-domain-policies` - -To disable the default values set the `spring.cloud.gateway.filter.secure-headers.disable` property with comma-separated values. -The following example shows how to do so: - -==== -[source] ----- -spring.cloud.gateway.filter.secure-headers.disable=x-frame-options,strict-transport-security ----- -==== - -NOTE: The lowercase full name of the secure header needs to be used to disable it.. - -[[the-setpath-gatewayfilter-factory]] -=== The `SetPath` `GatewayFilter` Factory - -The `SetPath` `GatewayFilter` factory takes a path `template` parameter. -It offers a simple way to manipulate the request path by allowing templated segments of the path. -This uses the URI templates from Spring Framework. -Multiple matching segments are allowed. -The following example configures a `SetPath` `GatewayFilter`: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: setpath_route - uri: https://example.org - predicates: - - Path=/red/{segment} - filters: - - SetPath=/{segment} ----- -==== - -For a request path of `/red/blue`, this sets the path to `/blue` before making the downstream request. - -[[the-setrequestheader-gatewayfilter-factory]] -=== The `SetRequestHeader` `GatewayFilter` Factory - -The `SetRequestHeader` `GatewayFilter` factory takes `name` and `value` parameters. -The following listing configures a `SetRequestHeader` `GatewayFilter`: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: setrequestheader_route - uri: https://example.org - filters: - - SetRequestHeader=X-Request-Red, Blue ----- -==== - -This `GatewayFilter` replaces (rather than adding) all headers with the given name. -So, if the downstream server responded with `X-Request-Red:1234`, it will be replaced with `X-Request-Red:Blue`, which is what the downstream service would receive. - -`SetRequestHeader` is aware of URI variables used to match a path or host. -URI variables may be used in the value and are expanded at runtime. -The following example configures an `SetRequestHeader` `GatewayFilter` that uses a variable: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: setrequestheader_route - uri: https://example.org - predicates: - - Host: {segment}.myhost.org - filters: - - SetRequestHeader=foo, bar-{segment} ----- -==== - -[[the-setresponseheader-gatewayfilter-factory]] -=== The `SetResponseHeader` `GatewayFilter` Factory - -The `SetResponseHeader` `GatewayFilter` factory takes `name` and `value` parameters. -The following listing configures a `SetResponseHeader` `GatewayFilter`: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: setresponseheader_route - uri: https://example.org - filters: - - SetResponseHeader=X-Response-Red, Blue ----- -==== - -This GatewayFilter replaces (rather than adding) all headers with the given name. -So, if the downstream server responded with `X-Response-Red:1234`, it will be replaced with `X-Response-Red:Blue`, which is what the gateway client would receive. - -`SetResponseHeader` is aware of URI variables used to match a path or host. -URI variables may be used in the value and will be expanded at runtime. -The following example configures an `SetResponseHeader` `GatewayFilter` that uses a variable: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: setresponseheader_route - uri: https://example.org - predicates: - - Host: {segment}.myhost.org - filters: - - SetResponseHeader=foo, bar-{segment} ----- -==== - -[[the-setstatus-gatewayfilter-factory]] -=== The `SetStatus` `GatewayFilter` Factory - -The `SetStatus` `GatewayFilter` factory takes a single parameter, `status`. -It must be a valid Spring `HttpStatus`. -It may be the integer value `404` or the string representation of the enumeration: `NOT_FOUND`. -The following listing configures a `SetStatus` `GatewayFilter`: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: setstatusstring_route - uri: https://example.org - filters: - - SetStatus=UNAUTHORIZED - - id: setstatusint_route - uri: https://example.org - filters: - - SetStatus=401 ----- -==== - -In either case, the HTTP status of the response is set to 401. - -You can configure the `SetStatus` `GatewayFilter` to return the original HTTP status code from the proxied request in a header in the response. -The header is added to the response if configured with the following property: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - set-status: - original-status-header-name: original-http-status ----- -==== - -[[the-stripprefix-gatewayfilter-factory]] -=== The `StripPrefix` `GatewayFilter` Factory - -The `StripPrefix` `GatewayFilter` factory takes one parameter, `parts`. -The `parts` parameter indicates the number of parts in the path to strip from the request before sending it downstream. -The following listing configures a `StripPrefix` `GatewayFilter`: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: nameRoot - uri: https://nameservice - predicates: - - Path=/name/** - filters: - - StripPrefix=2 ----- -==== - -When a request is made through the gateway to `/name/blue/red`, the request made to `nameservice` looks like `https://nameservice/red`. - -[[the-retry-gatewayfilter-factory]] -=== The `Retry` `GatewayFilter` Factory - -The `Retry` `GatewayFilter` factory supports the following parameters: - -* `retries`: The number of retries that should be attempted. -* `statuses`: The HTTP status codes that should be retried, represented by using `org.springframework.http.HttpStatus`. -* `methods`: The HTTP methods that should be retried, represented by using `org.springframework.http.HttpMethod`. -* `series`: The series of status codes to be retried, represented by using `org.springframework.http.HttpStatus.Series`. -* `exceptions`: A list of thrown exceptions that should be retried. -* `backoff`: The configured exponential backoff for the retries. -Retries are performed after a backoff interval of `firstBackoff * (factor ^ n)`, where `n` is the iteration. -If `maxBackoff` is configured, the maximum backoff applied is limited to `maxBackoff`. -If `basedOnPreviousValue` is true, the backoff is calculated by using `prevBackoff * factor`. - -The following defaults are configured for `Retry` filter, if enabled: - -* `retries`: Three times -* `series`: 5XX series -* `methods`: GET method -* `exceptions`: `IOException` and `TimeoutException` -* `backoff`: disabled - -The following listing configures a Retry `GatewayFilter`: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: retry_test - uri: http://localhost:8080/flakey - predicates: - - Host=*.retry.com - filters: - - name: Retry - args: - retries: 3 - statuses: BAD_GATEWAY - methods: GET,POST - backoff: - firstBackoff: 10ms - maxBackoff: 50ms - factor: 2 - basedOnPreviousValue: false ----- -==== - -NOTE: When using the retry filter with a `forward:` prefixed URL, the target endpoint should be written carefully so that, in case of an error, it does not do anything that could result in a response being sent to the client and committed. -For example, if the target endpoint is an annotated controller, the target controller method should not return `ResponseEntity` with an error status code. -Instead, it should throw an `Exception` or signal an error (for example, through a `Mono.error(ex)` return value), which the retry filter can be configured to handle by retrying. - -WARNING: When using the retry filter with any HTTP method with a body, the body will be cached and the gateway will become memory constrained. The body is cached in a request attribute defined by `ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR`. The type of the object is `org.springframework.core.io.buffer.DataBuffer`. - -A simplified "shortcut" notation can be added with a single `status` and `method`. - -The following two examples are equivalent: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: retry_route - uri: https://example.org - filters: - - name: Retry - args: - retries: 3 - statuses: INTERNAL_SERVER_ERROR - methods: GET - backoff: - firstBackoff: 10ms - maxBackoff: 50ms - factor: 2 - basedOnPreviousValue: false - - - id: retryshortcut_route - uri: https://example.org - filters: - - Retry=3,INTERNAL_SERVER_ERROR,GET,10ms,50ms,2,false ----- -==== - -[[the-requestsize-gatewayfilter-factory]] -=== The `RequestSize` `GatewayFilter` Factory - -When the request size is greater than the permissible limit, the `RequestSize` `GatewayFilter` factory can restrict a request from reaching the downstream service. -The filter takes a `maxSize` parameter. -The `maxSize` is a `DataSize` type, so values can be defined as a number followed by an optional `DataUnit` suffix such as 'KB' or 'MB'. The default is 'B' for bytes. -It is the permissible size limit of the request defined in bytes. -The following listing configures a `RequestSize` `GatewayFilter`: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: request_size_route - uri: http://localhost:8080/upload - predicates: - - Path=/upload - filters: - - name: RequestSize - args: - maxSize: 5000000 ----- -==== - -The `RequestSize` `GatewayFilter` factory sets the response status as `413 Payload Too Large` with an additional header `errorMessage` when the request is rejected due to size. The following example shows such an `errorMessage`: - -==== -[source] ----- -errorMessage : Request size is larger than permissible limit. Request size is 6.0 MB where permissible limit is 5.0 MB ----- -==== - -NOTE: The default request size is set to five MB if not provided as a filter argument in the route definition. - -[[the-setrequesthostheader-gatewayfilter-factory]] -=== The `SetRequestHostHeader` `GatewayFilter` Factory - -There are certain situation when the host header may need to be overridden. In this situation, the `SetRequestHostHeader` `GatewayFilter` factory can replace the existing host header with a specified value. -The filter takes a `host` parameter. -The following listing configures a `SetRequestHostHeader` `GatewayFilter`: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: set_request_host_header_route - uri: http://localhost:8080/headers - predicates: - - Path=/headers - filters: - - name: SetRequestHostHeader - args: - host: example.org ----- -==== - -The `SetRequestHostHeader` `GatewayFilter` factory replaces the value of the host header with `example.org`. - - -[[the-tokenrelay-gatewayfilter-factory]] -=== The `TokenRelay` `GatewayFilter` Factory - -A Token Relay is where an OAuth2 consumer acts as a Client and -forwards the incoming token to outgoing resource requests. The -consumer can be a pure Client (like an SSO application) or a Resource -Server. - -Spring Cloud Gateway can forward OAuth2 access tokens downstream to the services -it is proxying using the `TokenRelay` `GatewayFilter`. - -The `TokenRelay` `GatewayFilter` takes one optional parameter, `clientRegistrationId`. -The following example configures a `TokenRelay` `GatewayFilter`: - -.App.java -[source,java] ----- - -@Bean -public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { - return builder.routes() - .route("resource", r -> r.path("/resource") - .filters(f -> f.tokenRelay("myregistrationid")) - .uri("http://localhost:9000")) - .build(); -} ----- - -or this - -.application.yaml -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: resource - uri: http://localhost:9000 - predicates: - - Path=/resource - filters: - - TokenRelay=myregistrationid ----- - -The example above specifies a `clientRegistrationId`, which can be used to obtain and forward an OAuth2 access token for any available `ClientRegistration`. - -Spring Cloud Gateway can also forward the OAuth2 access token of the currently authenticated user `oauth2Login()` is used to authenticate the user. -To add this functionality to the gateway, you can omit the `clientRegistrationId` parameter like this: - -.App.java -[source,java] ----- - -@Bean -public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { - return builder.routes() - .route("resource", r -> r.path("/resource") - .filters(f -> f.tokenRelay()) - .uri("http://localhost:9000")) - .build(); -} ----- - -or this - -.application.yaml -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: resource - uri: http://localhost:9000 - predicates: - - Path=/resource - filters: - - TokenRelay= ----- - -and it will (in addition to logging the user in and grabbing a token) -pass the authentication token downstream to the services (in this case -`/resource`). - -To enable this for Spring Cloud Gateway add the following dependencies - -- `org.springframework.boot:spring-boot-starter-oauth2-client` - -How does it work? The {github-code}/src/main/java/org/springframework/cloud/gateway/security/TokenRelayGatewayFilterFactory.java[filter] -extracts an OAuth2 access token from the currently authenticated user for the provided `clientRegistrationId`. -If no `clientRegistrationId` is provided, the currently authenticated user's own access token (obtained during login) is used. -In either case, the extracted access token is placed in a request header for the downstream requests. - -For a full working sample see https://github.com/spring-cloud-samples/sample-gateway-oauth2login[this project]. - -NOTE: A `TokenRelayGatewayFilterFactory` bean will only be created if the proper `spring.security.oauth2.client.*` properties are set which will trigger creation of a `ReactiveClientRegistrationRepository` bean. - -NOTE: The default implementation of `ReactiveOAuth2AuthorizedClientService` used by `TokenRelayGatewayFilterFactory` -uses an in-memory data store. You will need to provide your own implementation `ReactiveOAuth2AuthorizedClientService` -if you need a more robust solution. - - -[[default-filters]] -=== Default Filters - -To add a filter and apply it to all routes, you can use `spring.cloud.gateway.default-filters`. -This property takes a list of filters. -The following listing defines a set of default filters: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - default-filters: - - AddResponseHeader=X-Response-Default-Red, Default-Blue - - PrefixPath=/httpbin ----- -==== - -[[global-filters]] -== Global Filters - -The `GlobalFilter` interface has the same signature as `GatewayFilter`. -These are special filters that are conditionally applied to all routes. - -NOTE: This interface and its usage are subject to change in future milestone releases. - -[[gateway-combined-global-filter-and-gatewayfilter-ordering]] -=== 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 <>), 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: - -.ExampleConfiguration.java -==== -[source,java] ----- -@Bean -public GlobalFilter customFilter() { - return new CustomGlobalFilter(); -} - -public class CustomGlobalFilter implements GlobalFilter, Ordered { - - @Override - public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { - log.info("custom global filter"); - return chain.filter(exchange); - } - - @Override - public int getOrder() { - return -1; - } -} ----- -==== - -[[the-gateway-metrics-filter]] -=== 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 `spring.cloud.gateway.metrics.enabled` property is not set to `false`. -This filter adds a timer metric named `spring.cloud.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 link:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/HttpStatus.Series.html[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. - -In addition, through the `spring.cloud.gateway.metrics.tags.path.enabled` property (by default, `false`), you can activate an extra metric with the path tag: - -* `path`: The path of the request. - -These metrics are then available to be scraped from `/actuator/metrics/spring.cloud.gateway.requests` and can be easily integrated with Prometheus to create a link:images/gateway-grafana-dashboard.jpeg[Grafana] link:gateway-grafana-dashboard.json[dashboard]. - -NOTE: To enable the prometheus endpoint, add `micrometer-registry-prometheus` as a project dependency. - -[[local-cache-response-global-filter]] -=== The Local Response Cache Filter - -The `LocalResponseCache` runs if associated properties are enabled: - -* `spring.cloud.gateway.global-filter.local-response-cache.enabled`: Activates the global cache for all routes -* `spring.cloud.gateway.filter.local-response-cache.enabled`: Activates the associated filter to use at route level - -This feature enables a local cache using Caffeine for all responses that meet the following criteria: - -* The request is a bodiless GET. -* The response has one of the following status codes: HTTP 200 (OK), HTTP 206 (Partial Content), or HTTP 301 (Moved Permanently). -* The HTTP `Cache-Control` header allows caching (that means it does not have any of the following values: `no-store` present in the request and `no-store` or `private` present in the response). - -It accepts two configuration parameters: - -* `spring.cloud.gateway.filter.local-response-cache.size`: Sets the maximum size of the cache to evict entries for this route (in KB, MB and GB). -* `spring.cloud.gateway.filter.local-response-cache.time-to-live` Sets the time to expire a cache entry (expressed in s for seconds, m for minutes, and h for hours). - -If none of these parameters are configured but the global filter is enabled, by default, it configures 5 minutes of time to live for the cached response. - -This filter also implements the automatic calculation of the `max-age` value in the HTTP `Cache-Control` header. -If `max-age` is present on the original response, the value is rewritten with the number of seconds set in the `timeToLive` configuration parameter. -In subsequent calls, this value is recalculated with the number of seconds left until the response expires. - -Setting `spring.cloud.gateway.global-filter.local-response-cache.enabled` to `false` deactivate the local response cache for all routes, the <> allows to use this functionality at route level. - -NOTE: To enable this feature, add `com.github.ben-manes.caffeine:caffeine` and `spring-boot-starter-cache` as project dependencies. - -WARNING: If your project creates custom `CacheManager` beans, it will either need to be marked with `@Primary` or injected using `@Qualifier`. - -[[forward-routing-filter]] -=== 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. - -[[the-netty-routing-filter]] -=== 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.) - -[[the-netty-write-response-filter]] -=== 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.) - -[[reactive-loadbalancer-client-filter]] -=== 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`: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: myRoute - uri: lb://service - predicates: - - Path=/service/** ----- -==== - -NOTE: 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`. - -NOTE: 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. - -TIP: Gateway supports all the LoadBalancer features. You can read more about them in the https://docs.spring.io/spring-cloud-commons/docs/current/reference/html/#spring-cloud-loadbalancer[Spring Cloud Commons documentation]. - -[[the-routetorequesturl-filter]] -=== 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. - -If the URI has a scheme prefix, such as `lb:ws://serviceid`, the `lb` scheme is stripped from the URI and placed in the `ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR` for use later in the filter chain. - -[[the-websocket-routing-filter]] -=== The Websocket Routing Filter - -If 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`. - -NOTE: If you use https://github.com/sockjs[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: - -.application.yml -==== -[source,yaml] ----- -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/** ----- -==== - -[[marking-an-exchange-as-routed]] -=== 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 a `ServerWebExchange` object and checks if it has been "`routed`". -* `ServerWebExchangeUtils.setAlreadyRouted` takes a `ServerWebExchange` object and marks it as "`routed`". - -[[httpheadersfilters]] -== HttpHeadersFilters - -`HttpHeadersFilters` are applied to the requests before sending them downstream, such as in the `NettyRoutingFilter`. - -[[forwarded-headers-filter]] -=== 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. - -[[removehopbyhop-headers-filter]] -=== RemoveHopByHop Headers Filter -The `RemoveHopByHop` Headers Filter removes headers from forwarded requests. The default list of headers that is removed comes from the https://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-14#section-7.1.3[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. - -[[xforwarded-headers-filter]] -=== XForwarded Headers Filter -The `XForwarded` Headers Filter creates various `X-Forwarded-*` headers to send to the downstream service. It uses 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` - -[[tls-and-ssl]] -== 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: - -.application.yml -==== -[source,yaml] ----- -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: - -.application.yml -==== -[source,yaml] ----- -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: - -.application.yml -==== -[source,yaml] ----- -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). - -[[tls-handshake]] -=== 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: - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - httpclient: - ssl: - handshake-timeout-millis: 10000 - close-notify-flush-timeout-millis: 3000 - close-notify-read-timeout-millis: 0 ----- -==== - -[[configuration]] -== Configuration - -Configuration for Spring Cloud Gateway is driven by a collection of `RouteDefinitionLocator` instances. -The following listing shows the definition of the `RouteDefinitionLocator` interface: - -.RouteDefinitionLocator.java -==== -[source,java] ----- -public interface RouteDefinitionLocator { - Flux 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: - -.application.yml -==== -[source,yaml] ----- -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. - -[[routedefinition-metrics]] -=== RouteDefinition Metrics - -To enable `RouteDefinition` metrics, add spring-boot-starter-actuator as a project dependency. Then, by default, the metrics will be available as long as the property `spring.cloud.gateway.metrics.enabled` is set to `true`. A gauge metric named `spring.cloud.gateway.routes.count` will be added, whose value is the number of `RouteDefinitions`. This metric will be available from `/actuator/metrics/spring.cloud.gateway.routes.count`. - -[[route-metadata-configuration]] -== Route Metadata Configuration - -You can configure additional parameters for each route by using metadata, as follows: - -.application.yml -==== -[source,yaml] ----- -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: - -==== -[source] ----- -Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR); -// get all metadata properties -route.getMetadata(); -// get a single metadata property -route.getMetadata(someKey); ----- -==== - -[[http-timeouts-configuration]] -== Http timeouts configuration - -Http timeouts (response and connect) can be configured for all routes and overridden for each specific route. - -[[global-timeouts]] -=== 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 -[source,yaml] ----- -spring: - cloud: - gateway: - httpclient: - connect-timeout: 1000 - response-timeout: 5s ----- - -[[per-route-timeouts]] -=== 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 -[source,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 -[source,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(); - } ----- - -A per-route `response-timeout` with a negative value will disable the global `response-timeout` value. - ----- - - id: per_route_timeouts - uri: https://example.org - predicates: - - name: Path - args: - pattern: /delay/{timeout} - metadata: - response-timeout: -1 ----- - -[[fluent-java-routes-api]] -== 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: - -.GatewaySampleApplication.java -==== -[source,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. - -[[the-discoveryclient-route-definition-locator]] -== 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. - -[[configuring-predicates-and-filters-for-discoveryclient-routes]] -=== 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/?(?.*)` 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: - -.application.properties -==== -[soure,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 + '/?(?.*)'" -spring.cloud.gateway.discovery.locator.filters[1].args[replacement]: "'/${remaining}'" ----- -==== - -[[reactor-netty-access-logs]] -== Reactor Netty Access Logs - -To enable Reactor Netty access logs, set `-Dreactor.netty.http.server.accessLogEnabled=true`. - -IMPORTANT: 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: - -.logback.xml -==== -[source,xml] ----- - - access_log.log - - %msg%n - - - - - - - - - ----- -==== - -[[cors-configuration]] -== CORS Configuration -:cors-configuration-docs-uri: https://docs.spring.io/spring/docs/5.0.x/javadoc-api/org/springframework/web/cors/CorsConfiguration.html - -You can configure the gateway to control CORS behavior globally or per route. -Both offer the same possibilities. - -[[global-cors-configuration]] -=== Global CORS Configuration - -The "`global`" CORS configuration is a map of URL patterns to {cors-configuration-docs-uri}[Spring Framework `CorsConfiguration`]. -The following example configures CORS: - -.application.yml -==== -[source,yaml] ----- -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 evaluate to `true` because the HTTP method is `options`. - -[[route-cors-configuration]] -=== Route CORS Configuration - -The "`route`" configuration allows applying CORS directly to a route as metadata with key `cors`. -Like in the case of global configuration, the properties belong to {cors-configuration-docs-uri}[Spring Framework `CorsConfiguration`]. - -NOTE: If no `Path` predicate is present in the route '/**' will be applied. - -.application.yml -==== -[source,yaml] ----- -spring: - cloud: - gateway: - routes: - - id: cors_route - uri: https://example.org - predicates: - - Path=/service/** - metadata: - cors - allowedOrigins: '*' - allowedMethods: - - GET - - POST - allowedHeaders: '*' - maxAge: 30 ----- -==== - -[[actuator-api]] -== 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 https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html#production-ready-endpoints-enabling-endpoints[enabled] and https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html#production-ready-endpoints-exposing-endpoints[exposed over HTTP or JMX] in the application properties. -The following listing shows how to do so: - -.application.properties -==== -[source,properties] ----- -management.endpoint.gateway.enabled=true # default value -management.endpoints.web.exposure.include=gateway ----- -==== - -[[verbose-actuator-format]] -=== 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`: - -==== -[source,json] ----- -[ - { - "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: - -.application.properties -==== -[source,properties] ----- -spring.cloud.gateway.actuator.verbose.enabled=false ----- -==== - -This will default to `true` in a future release. - -[[retrieving-route-filters]] -=== Retrieving Route Filters - -This section details how to retrieve route filters, including: - -* <> -* <> - -[[gateway-global-filters]] -==== Global Filters - -To retrieve the <> 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 <> in the filter chain. - -[[gateway-route-filters]] -==== Route Filters -To retrieve the <> 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. - -[[refreshing-the-route-cache]] -=== 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. - -To clear the routes with specific metadata values, add the Query parameter `metadata` specifying the `key:value` pairs that the routes to be cleared should match. -If an error is produced during the asynchronous refresh, the refresh will not modify the existing routes. - -Sending `POST` request to `/actuator/gateway/refresh?metadata=group:group-1` will only refresh the routes whose `group` metadata is `group-1`: `first_route` and `third_route`. -==== -[source,json] ----- -[{ - "route_id": "first_route", - "route_object": { - "predicate": "...", - }, - "metadata": { "group": "group-1" } -}, -{ - "route_id": "second_route", - "route_object": { - "predicate": "...", - }, - "metadata": { "group": "group-2" } -}, -{ - "route_id": "third_route", - "route_object": { - "predicate": "...", - }, - "metadata": { "group": "group-1" } -}] ----- -==== - -[[retrieving-the-routes-defined-in-the-gateway]] -=== 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: - -[cols="3,2,4"] -|=== -| Path | Type | Description - -|`route_id` -| String -| The route ID. - -|`route_object.predicate` -| Object -| The route predicate. - -|`route_object.filters` -| Array -| The <> applied to the route. - -|`order` -| Number -| The route order. - -|=== - -[[gateway-retrieving-information-about-a-particular-route]] -=== 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: - -[cols="3,2,4"] -|=== -| 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. - -|=== - -[[creating-and-deleting-a-particular-route-definition]] -=== Creating and Deleting a Particular Route Definition - -To create a route definition, make a `POST` request to `/gateway/routes/{id_route_to_create}` with a JSON body that specifies the fields of the route (see <>). - -To delete a route definition, make a `DELETE` request to `/gateway/routes/{id_route_to_delete}`. - -[[creating-multiple-route-definitions]] -=== Creating multiple Route Definitions - -To create multiple route definitions in a single request, make a `POST` request to `/gateway/routes` with a JSON body that specifies the fields of the route, including the route id (see <>). - -The route definitions will be discarded if any route raises an error during the creation of the routes. - -[[recap:-the-list-of-all-endpoints]] -=== Recap: The List of All endpoints - -The following table below summarizes the Spring Cloud Gateway actuator endpoints (note that each endpoint has `/actuator/gateway` as the base-path): - -[cols="2,2,5"] -|=== -| 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. - -|=== - -[[sharing-routes-between-multiple-gateway-instances]] -=== Sharing Routes between multiple Gateway instances -Spring Cloud Gateway offers two `RouteDefinitionRepository` implementations. The first one is the -`InMemoryRouteDefinitionRepository` which only lives within the memory of one Gateway instance. -This type of Repository is not suited to populate Routes across multiple Gateway instances. - -In order to share Routes across a cluster of Spring Cloud Gateway instances, `RedisRouteDefinitionRepository` can be used. -To enable this kind of repository, the following property has to set to true: `spring.cloud.gateway.redis-route-definition-repository.enabled` -Likewise to the RedisRateLimiter Filter Factory it requires the use of the spring-boot-starter-data-redis-reactive Spring Boot starter. - -[[troubleshooting]] -== Troubleshooting - -This section covers common problems that may arise when you use Spring Cloud Gateway. - -[[log-levels]] -=== 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` - -[[wiretap]] -=== 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. - -[[developer-guide]] -== Developer Guide - -These are basic guides to writing some custom components of the gateway. - -[[writing-custom-route-predicate-factories]] -=== Writing Custom Route Predicate Factories - - -In order to write a Route Predicate you will need to implement `RoutePredicateFactory` as a bean. There is an abstract class called `AbstractRoutePredicateFactory` which you can extend. - -.MyRoutePredicateFactory.java -[source,java] ----- -@Component -public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory { - - public MyRoutePredicateFactory() { - super(Config.class); - } - - @Override - public Predicate 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 - } - -} ----- -[[writing-custom-gatewayfilter-factories]] -=== Writing Custom GatewayFilter Factories - -To write a `GatewayFilter`, you must implement `GatewayFilterFactory` as a bean. -You can extend an abstract class called `AbstractGatewayFilterFactory`. -The following examples show how to do so: - -.PreGatewayFilterFactory.java -==== -[source,java] ----- -@Component -public class PreGatewayFilterFactory extends AbstractGatewayFilterFactory { - - 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 -[source,java] ----- -@Component -public class PostGatewayFilterFactory extends AbstractGatewayFilterFactory { - - 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 - } - -} ----- -==== - -[[naming-custom-filters-and-references-in-configuration]] -==== 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`. - -WARNING: It is possible to create a gateway filter named without the -`GatewayFilterFactory` 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. - -[[writing-custom-global-filters]] -=== Writing Custom Global Filters - -To write a custom global filter, you must implement `GlobalFilter` interface as a bean. -This applies the filter to all requests. - -The following examples show how to set up global pre- and post-filters, respectively: - -==== -[source,java] ----- -@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(); -} ----- -==== - -[[building-a-simple-gateway-by-using-spring-mvc-or-webflux]] -== Building a Simple Gateway by Using Spring MVC or Webflux - -WARNING: 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: - -==== -[source,java] ----- -@RestController -@SpringBootApplication -public class GatewaySampleApplication { - - @Value("${remote.home}") - private URI home; - - @GetMapping("/test") - public ResponseEntity proxy(ProxyExchange proxy) throws Exception { - return proxy.uri(home.toString() + "/image/png").get(); - } - -} ----- -==== - -The following example does the same thing with Webflux: - -==== -[source,java] ----- -@RestController -@SpringBootApplication -public class GatewaySampleApplication { - - @Value("${remote.home}") - private URI home; - - @GetMapping("/test") - public Mono> proxy(ProxyExchange 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: - -==== -[source,java] ----- -@GetMapping("/proxy/path/**") -public ResponseEntity proxyPath(ProxyExchange 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. - -[[aot-and-native-image-support]] -== AOT and Native Image Support - -Since `4.0.0`, Spring Cloud Gateway supports Spring AOT transformations and native images. - -TIP: If you're using load-balanced routes, you need to explicitly define your `LoadBalancerClient` service IDs. You can do so by using the `value` or `name` attributes of the `@LoadBalancerClient` annotation or as values of the `spring.cloud.loadbalancer.eager-load.clients` property. - -[[configuration-properties]] -== Configuration properties - -To see the list of all Spring Cloud Gateway related configuration properties, see link:appendix.html[the appendix]. diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/actuator-api.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/actuator-api.adoc new file mode 100644 index 00000000..e7121585 --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/actuator-api.adoc @@ -0,0 +1,307 @@ +[[actuator-api]] += 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 https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html#production-ready-endpoints-enabling-endpoints[enabled] and https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html#production-ready-endpoints-exposing-endpoints[exposed over HTTP or JMX] in the application properties. +The following listing shows how to do so: + +.application.properties +==== +[source,properties] +---- +management.endpoint.gateway.enabled=true # default value +management.endpoints.web.exposure.include=gateway +---- +==== + +[[verbose-actuator-format]] +== 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`: + +==== +[source,json] +---- +[ + { + "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: + +.application.properties +==== +[source,properties] +---- +spring.cloud.gateway.actuator.verbose.enabled=false +---- +==== + +This will default to `true` in a future release. + +[[retrieving-route-filters]] +== Retrieving Route Filters + +This section details how to retrieve route filters, including: + +* <> +* <> + +[[gateway-global-filters]] +=== Global Filters + +To retrieve the <> 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 <> in the filter chain. + +[[gateway-route-filters]] +=== Route Filters +To retrieve the <> 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. + +[[refreshing-the-route-cache]] +== 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. + +To clear the routes with specific metadata values, add the Query parameter `metadata` specifying the `key:value` pairs that the routes to be cleared should match. +If an error is produced during the asynchronous refresh, the refresh will not modify the existing routes. + +Sending `POST` request to `/actuator/gateway/refresh?metadata=group:group-1` will only refresh the routes whose `group` metadata is `group-1`: `first_route` and `third_route`. +==== +[source,json] +---- +[{ + "route_id": "first_route", + "route_object": { + "predicate": "...", + }, + "metadata": { "group": "group-1" } +}, +{ + "route_id": "second_route", + "route_object": { + "predicate": "...", + }, + "metadata": { "group": "group-2" } +}, +{ + "route_id": "third_route", + "route_object": { + "predicate": "...", + }, + "metadata": { "group": "group-1" } +}] +---- +==== + +[[retrieving-the-routes-defined-in-the-gateway]] +== 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: + +[cols="3,2,4"] +|=== +| Path | Type | Description + +|`route_id` +| String +| The route ID. + +|`route_object.predicate` +| Object +| The route predicate. + +|`route_object.filters` +| Array +| The <> applied to the route. + +|`order` +| Number +| The route order. + +|=== + +[[gateway-retrieving-information-about-a-particular-route]] +== 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: + +[cols="3,2,4"] +|=== +| 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. + +|=== + +[[creating-and-deleting-a-particular-route-definition]] +== Creating and Deleting a Particular Route Definition + +To create a route definition, make a `POST` request to `/gateway/routes/{id_route_to_create}` with a JSON body that specifies the fields of the route (see <>). + +To delete a route definition, make a `DELETE` request to `/gateway/routes/{id_route_to_delete}`. + +[[creating-multiple-route-definitions]] +== Creating multiple Route Definitions + +To create multiple route definitions in a single request, make a `POST` request to `/gateway/routes` with a JSON body that specifies the fields of the route, including the route id (see <>). + +The route definitions will be discarded if any route raises an error during the creation of the routes. + +[[recap:-the-list-of-all-endpoints]] +== Recap: The List of All endpoints + +The following table below summarizes the Spring Cloud Gateway actuator endpoints (note that each endpoint has `/actuator/gateway` as the base-path): + +[cols="2,2,5"] +|=== +| 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. + +|=== + +[[sharing-routes-between-multiple-gateway-instances]] +== Sharing Routes between multiple Gateway instances +Spring Cloud Gateway offers two `RouteDefinitionRepository` implementations. The first one is the +`InMemoryRouteDefinitionRepository` which only lives within the memory of one Gateway instance. +This type of Repository is not suited to populate Routes across multiple Gateway instances. + +In order to share Routes across a cluster of Spring Cloud Gateway instances, `RedisRouteDefinitionRepository` can be used. +To enable this kind of repository, the following property has to set to true: `spring.cloud.gateway.redis-route-definition-repository.enabled` +Likewise to the RedisRateLimiter Filter Factory it requires the use of the spring-boot-starter-data-redis-reactive Spring Boot starter. + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/aot-and-native-image-support.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/aot-and-native-image-support.adoc new file mode 100644 index 00000000..5663a22e --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/aot-and-native-image-support.adoc @@ -0,0 +1,7 @@ +[[aot-and-native-image-support]] += AOT and Native Image Support + +Since `4.0.0`, Spring Cloud Gateway supports Spring AOT transformations and native images. + +TIP: If you're using load-balanced routes, you need to explicitly define your `LoadBalancerClient` service IDs. You can do so by using the `value` or `name` attributes of the `@LoadBalancerClient` annotation or as values of the `spring.cloud.loadbalancer.eager-load.clients` property. + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/building-a-simple-by-using-mvc-or-webflux.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/building-a-simple-by-using-mvc-or-webflux.adoc new file mode 100644 index 00000000..497d89dd --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/building-a-simple-by-using-mvc-or-webflux.adoc @@ -0,0 +1,78 @@ +[[building-a-simple-gateway-by-using-spring-mvc-or-webflux]] += Building a Simple Gateway by Using Spring MVC or Webflux + +WARNING: 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: + +==== +[source,java] +---- +@RestController +@SpringBootApplication +public class GatewaySampleApplication { + + @Value("${remote.home}") + private URI home; + + @GetMapping("/test") + public ResponseEntity proxy(ProxyExchange proxy) throws Exception { + return proxy.uri(home.toString() + "/image/png").get(); + } + +} +---- +==== + +The following example does the same thing with Webflux: + +==== +[source,java] +---- +@RestController +@SpringBootApplication +public class GatewaySampleApplication { + + @Value("${remote.home}") + private URI home; + + @GetMapping("/test") + public Mono> proxy(ProxyExchange 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: + +==== +[source,java] +---- +@GetMapping("/proxy/path/**") +public ResponseEntity proxyPath(ProxyExchange 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. + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/configuration-properties.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/configuration-properties.adoc new file mode 100644 index 00000000..d8f06ccb --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/configuration-properties.adoc @@ -0,0 +1,4 @@ +[[configuration-properties]] += Configuration properties + +To see the list of all Spring Cloud Gateway related configuration properties, see link:appendix.html[the appendix]. diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/configuration.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/configuration.adoc new file mode 100644 index 00000000..ac430450 --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/configuration.adoc @@ -0,0 +1,49 @@ +[[configuration]] += Configuration + +Configuration for Spring Cloud Gateway is driven by a collection of `RouteDefinitionLocator` instances. +The following listing shows the definition of the `RouteDefinitionLocator` interface: + +.RouteDefinitionLocator.java +==== +[source,java] +---- +public interface RouteDefinitionLocator { + Flux 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: + +.application.yml +==== +[source,yaml] +---- +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. + +[[routedefinition-metrics]] +== RouteDefinition Metrics + +To enable `RouteDefinition` metrics, add spring-boot-starter-actuator as a project dependency. Then, by default, the metrics will be available as long as the property `spring.cloud.gateway.metrics.enabled` is set to `true`. A gauge metric named `spring.cloud.gateway.routes.count` will be added, whose value is the number of `RouteDefinitions`. This metric will be available from `/actuator/metrics/spring.cloud.gateway.routes.count`. + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/configuring-route-predicate-factories-and-filter-factories.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/configuring-route-predicate-factories-and-filter-factories.adoc new file mode 100644 index 00000000..9ab70bad --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/configuring-route-predicate-factories-and-filter-factories.adoc @@ -0,0 +1,50 @@ +[[configuring-route-predicate-factories-and-gateway-filter-factories]] += Configuring Route Predicate Factories and Gateway Filter Factories + +There are two ways to configure predicates and filters: shortcuts and fully expanded arguments. Most examples below use the shortcut way. + +The name and argument names are listed as `code` in the first sentence or two of each section. The arguments are typically listed in the order that are needed for the shortcut configuration. + +[[shortcut-configuration]] +== Shortcut Configuration + +Shortcut configuration is recognized by the filter name, followed by an equals sign (`=`), followed by argument values separated by commas (`,`). + +.application.yml +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: after_route + uri: https://example.org + predicates: + - Cookie=mycookie,mycookievalue +---- + +The previous sample defines the `Cookie` Route Predicate Factory with two arguments, the cookie name, `mycookie` and the value to match `mycookievalue`. + +[[fully-expanded-arguments]] +== Fully Expanded Arguments + +Fully expanded arguments appear more like standard yaml configuration with name/value pairs. Typically, there will be a `name` key and an `args` key. The `args` key is a map of key value pairs to configure the predicate or filter. + +.application.yml +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: after_route + uri: https://example.org + predicates: + - name: Cookie + args: + name: mycookie + regexp: mycookievalue +---- + +This is the full configuration of the shortcut configuration of the `Cookie` predicate shown above. + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/cors-configuration.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/cors-configuration.adoc new file mode 100644 index 00000000..a2e9ae24 --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/cors-configuration.adoc @@ -0,0 +1,65 @@ +[[cors-configuration]] += CORS Configuration +:cors-configuration-docs-uri: https://docs.spring.io/spring/docs/5.0.x/javadoc-api/org/springframework/web/cors/CorsConfiguration.html + +You can configure the gateway to control CORS behavior globally or per route. +Both offer the same possibilities. + +[[global-cors-configuration]] +== Global CORS Configuration + +The "`global`" CORS configuration is a map of URL patterns to {cors-configuration-docs-uri}[Spring Framework `CorsConfiguration`]. +The following example configures CORS: + +.application.yml +==== +[source,yaml] +---- +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 evaluate to `true` because the HTTP method is `options`. + +[[route-cors-configuration]] +== Route CORS Configuration + +The "`route`" configuration allows applying CORS directly to a route as metadata with key `cors`. +Like in the case of global configuration, the properties belong to {cors-configuration-docs-uri}[Spring Framework `CorsConfiguration`]. + +NOTE: If no `Path` predicate is present in the route '/**' will be applied. + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: cors_route + uri: https://example.org + predicates: + - Path=/service/** + metadata: + cors + allowedOrigins: '*' + allowedMethods: + - GET + - POST + allowedHeaders: '*' + maxAge: 30 +---- +==== + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/developer-guide.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/developer-guide.adoc new file mode 100644 index 00000000..36123fdc --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/developer-guide.adoc @@ -0,0 +1,158 @@ +[[developer-guide]] += Developer Guide + +These are basic guides to writing some custom components of the gateway. + +[[writing-custom-route-predicate-factories]] +== Writing Custom Route Predicate Factories + + +In order to write a Route Predicate you will need to implement `RoutePredicateFactory` as a bean. There is an abstract class called `AbstractRoutePredicateFactory` which you can extend. + +.MyRoutePredicateFactory.java +[source,java] +---- +@Component +public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory { + + public MyRoutePredicateFactory() { + super(Config.class); + } + + @Override + public Predicate 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 + } + +} +---- +[[writing-custom-gatewayfilter-factories]] +== Writing Custom GatewayFilter Factories + +To write a `GatewayFilter`, you must implement `GatewayFilterFactory` as a bean. +You can extend an abstract class called `AbstractGatewayFilterFactory`. +The following examples show how to do so: + +.PreGatewayFilterFactory.java +==== +[source,java] +---- +@Component +public class PreGatewayFilterFactory extends AbstractGatewayFilterFactory { + + 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 +[source,java] +---- +@Component +public class PostGatewayFilterFactory extends AbstractGatewayFilterFactory { + + 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 + } + +} +---- +==== + +[[naming-custom-filters-and-references-in-configuration]] +=== 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`. + +WARNING: It is possible to create a gateway filter named without the +`GatewayFilterFactory` 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. + +[[writing-custom-global-filters]] +== Writing Custom Global Filters + +To write a custom global filter, you must implement `GlobalFilter` interface as a bean. +This applies the filter to all requests. + +The following examples show how to set up global pre- and post-filters, respectively: + +==== +[source,java] +---- +@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(); +} +---- +==== + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/fluent-java-routes-api.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/fluent-java-routes-api.adoc new file mode 100644 index 00000000..67b5c7ca --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/fluent-java-routes-api.adoc @@ -0,0 +1,43 @@ +[[fluent-java-routes-api]] += 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: + +.GatewaySampleApplication.java +==== +[source,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. + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories.adoc new file mode 100644 index 00000000..c1664116 --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories.adoc @@ -0,0 +1,9 @@ +[[gatewayfilter-factories]] += `GatewayFilter` Factories + +Route filters allow the modification of the incoming HTTP request or outgoing HTTP response in some manner. +Route filters are scoped to a particular route. +Spring Cloud Gateway includes many built-in GatewayFilter Factories. + +NOTE: For more detailed examples of how to use any of the following filters, take a look at the https://github.com/spring-cloud/spring-cloud-gateway/tree/master/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory[unit tests]. + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/circuitbreaker-filter-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/circuitbreaker-filter-factory.adoc new file mode 100644 index 00000000..cb401860 --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/circuitbreaker-filter-factory.adoc @@ -0,0 +1,182 @@ +[[spring-cloud-circuitbreaker-filter-factory]] += The `CircuitBreaker` `GatewayFilter` Factory + +The Spring Cloud CircuitBreaker GatewayFilter factory uses the Spring Cloud CircuitBreaker APIs to wrap Gateway routes in +a circuit breaker. Spring Cloud CircuitBreaker supports multiple libraries that can be used with Spring Cloud Gateway. Spring Cloud supports Resilience4J out of the box. + +To enable the Spring Cloud CircuitBreaker filter, you need to place `spring-cloud-starter-circuitbreaker-reactor-resilience4j` on the classpath. +The following example configures a Spring Cloud CircuitBreaker `GatewayFilter`: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: circuitbreaker_route + uri: https://example.org + filters: + - CircuitBreaker=myCircuitBreaker +---- +==== + +To configure the circuit breaker, see the configuration for the underlying circuit breaker implementation you are using. + +* https://cloud.spring.io/spring-cloud-circuitbreaker/reference/html/spring-cloud-circuitbreaker.html[Resilience4J Documentation] + +The Spring Cloud CircuitBreaker filter can also accept an optional `fallbackUri` parameter. +Currently, only `forward:` schemed URIs are supported. +If the fallback is called, the request is forwarded to the controller matched by the URI. +The following example configures such a fallback: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: circuitbreaker_route + uri: lb://backing-service:8088 + predicates: + - Path=/consumingServiceEndpoint + filters: + - name: CircuitBreaker + args: + name: myCircuitBreaker + fallbackUri: forward:/inCaseOfFailureUseThis + - RewritePath=/consumingServiceEndpoint, /backingServiceEndpoint +---- +==== + +The following listing does the same thing in Java: + +.Application.java +==== +[source,java] +---- +@Bean +public RouteLocator routes(RouteLocatorBuilder builder) { + return builder.routes() + .route("circuitbreaker_route", r -> r.path("/consumingServiceEndpoint") + .filters(f -> f.circuitBreaker(c -> c.name("myCircuitBreaker").fallbackUri("forward:/inCaseOfFailureUseThis")) + .rewritePath("/consumingServiceEndpoint", "/backingServiceEndpoint")).uri("lb://backing-service:8088") + .build(); +} +---- +==== + +This example forwards to the `/inCaseofFailureUseThis` URI when the circuit breaker fallback is called. +Note that this example also demonstrates the (optional) Spring Cloud LoadBalancer load-balancing (defined by the `lb` prefix on the destination URI). + +CircuitBreaker also supports URI variables in the `fallbackUri`. +This allows more complex routing options, like forwarding sections of the original host or url path using https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/util/pattern/PathPattern.html[PathPattern expression]. + +In the example below the call `consumingServiceEndpoint/users/1` will be redirected to `inCaseOfFailureUseThis/users/1`. + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: circuitbreaker_route + uri: lb://backing-service:8088 + predicates: + - Path=/consumingServiceEndpoint/{*segments} + filters: + - name: CircuitBreaker + args: + name: myCircuitBreaker + fallbackUri: forward:/inCaseOfFailureUseThis/{segments} +---- +==== + +The primary scenario is to use the `fallbackUri` to define an internal controller or handler within the gateway application. +However, you can also reroute the request to a controller or handler in an external application, as follows: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: ingredients + uri: lb://ingredients + predicates: + - Path=//ingredients/** + filters: + - name: CircuitBreaker + args: + name: fetchIngredients + fallbackUri: forward:/fallback + - id: ingredients-fallback + uri: http://localhost:9994 + predicates: + - Path=/fallback +---- +==== + +In this example, there is no `fallback` endpoint or handler in the gateway application. +However, there is one in another application, registered under `http://localhost:9994`. + +In case of the request being forwarded to fallback, the Spring Cloud CircuitBreaker Gateway filter also provides the `Throwable` that has caused it. +It is added to the `ServerWebExchange` as the `ServerWebExchangeUtils.CIRCUITBREAKER_EXECUTION_EXCEPTION_ATTR` attribute that can be used when handling the fallback within the gateway application. + +For the external controller/handler scenario, headers can be added with exception details. +You can find more information on doing so in the <>. + +[[circuit-breaker-status-codes]] +== Tripping The Circuit Breaker On Status Codes + +In some cases you might want to trip a circuit breaker based on the status code +returned from the route it wraps. The circuit breaker config object takes a list of +status codes that if returned will cause the circuit breaker to be tripped. When setting the +status codes you want to trip the circuit breaker you can either use an integer with the status code +value or the String representation of the `HttpStatus` enumeration. + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: circuitbreaker_route + uri: lb://backing-service:8088 + predicates: + - Path=/consumingServiceEndpoint + filters: + - name: CircuitBreaker + args: + name: myCircuitBreaker + fallbackUri: forward:/inCaseOfFailureUseThis + statusCodes: + - 500 + - "NOT_FOUND" +---- +==== + +.Application.java +==== +[source,java] +---- +@Bean +public RouteLocator routes(RouteLocatorBuilder builder) { + return builder.routes() + .route("circuitbreaker_route", r -> r.path("/consumingServiceEndpoint") + .filters(f -> f.circuitBreaker(c -> c.name("myCircuitBreaker").fallbackUri("forward:/inCaseOfFailureUseThis").addStatusCode("INTERNAL_SERVER_ERROR")) + .rewritePath("/consumingServiceEndpoint", "/backingServiceEndpoint")).uri("lb://backing-service:8088") + .build(); +} +---- +==== + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/default-filters.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/default-filters.adoc new file mode 100644 index 00000000..7938506d --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/default-filters.adoc @@ -0,0 +1,20 @@ +[[default-filters]] += Default Filters + +To add a filter and apply it to all routes, you can use `spring.cloud.gateway.default-filters`. +This property takes a list of filters. +The following listing defines a set of default filters: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + default-filters: + - AddResponseHeader=X-Response-Default-Red, Default-Blue + - PrefixPath=/httpbin +---- +==== + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/fallback-headers.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/fallback-headers.adoc new file mode 100644 index 00000000..645b003d --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/fallback-headers.adoc @@ -0,0 +1,45 @@ +[[fallback-headers]] += The `FallbackHeaders` `GatewayFilter` Factory + +The `FallbackHeaders` factory lets you add Spring Cloud CircuitBreaker execution exception details in the headers of a request forwarded to a `fallbackUri` in an external application, as in the following scenario: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: ingredients + uri: lb://ingredients + predicates: + - Path=//ingredients/** + filters: + - name: CircuitBreaker + args: + name: fetchIngredients + fallbackUri: forward:/fallback + - id: ingredients-fallback + uri: http://localhost:9994 + predicates: + - Path=/fallback + filters: + - name: FallbackHeaders + args: + executionExceptionTypeHeaderName: Test-Header +---- +==== + +In this example, after an execution exception occurs while running the circuit breaker, the request is forwarded to the `fallback` endpoint or handler in an application running on `localhost:9994`. +The headers with the exception type, message and (if available) root cause exception type and message are added to that request by the `FallbackHeaders` filter. + +You can overwrite the names of the headers in the configuration by setting the values of the following arguments (shown with their default values): + +* `executionExceptionTypeHeaderName` (`"Execution-Exception-Type"`) +* `executionExceptionMessageHeaderName` (`"Execution-Exception-Message"`) +* `rootCauseExceptionTypeHeaderName` (`"Root-Cause-Exception-Type"`) +* `rootCauseExceptionMessageHeaderName` (`"Root-Cause-Exception-Message"`) + +For more information on circuit breakers and the gateway see the <>. + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/local-cache-response-filter.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/local-cache-response-filter.adoc new file mode 100644 index 00000000..e7a3d01f --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/local-cache-response-filter.adoc @@ -0,0 +1,57 @@ +[[local-cache-response-filter]] += The `LocalResponseCache` `GatewayFilter` Factory + +This filter allows caching the response body and headers to follow these rules: + +* It can only cache bodiless GET requests. +* It caches the response only for one of the following status codes: HTTP 200 (OK), HTTP 206 (Partial Content), or HTTP 301 (Moved Permanently). +* Response data is not cached if `Cache-Control` header does not allow it (`no-store` present in the request or `no-store` or `private` present in the response). +* If the response is already cached and a new request is performed with no-cache value in `Cache-Control` header, it returns a bodiless response with 304 (Not Modified). + +This filter configures the local response cache per route and is available only if the `spring.cloud.gateway.filter.local-response-cache.enabled` property is enabled. And a <> is also available as feature. + +It accepts the first parameter to override the time to expire a cache entry (expressed in `s` for seconds, `m` for minutes, and `h` for hours) and a second parameter to set the maximum size of the cache to evict entries for this route (`KB`, `MB`, or `GB`). + +The following listing shows how to add local response cache `GatewayFilter`: + +==== +[source,java] +---- +@Bean +public RouteLocator routes(RouteLocatorBuilder builder) { + return builder.routes() + .route("rewrite_response_upper", r -> r.host("*.rewriteresponseupper.org") + .filters(f -> f.prefixPath("/httpbin") + .localResponseCache(Duration.ofMinutes(30), "500MB") + ).uri(uri)) + .build(); +} +---- + +or this + +.application.yaml +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: resource + uri: http://localhost:9000 + predicates: + - Path=/resource + filters: + - LocalResponseCache=30m,500MB +---- +==== + +NOTE: This filter also automatically calculates the `max-age` value in the HTTP `Cache-Control` header. +Only if `max-age` is present on the original response is the value rewritten with the number of seconds set in the `timeToLive` configuration parameter. +In consecutive calls, this value is recalculated with the number of seconds left until the response expires. + +NOTE: To enable this feature, add `com.github.ben-manes.caffeine:caffeine` and `spring-boot-starter-cache` as project dependencies. + +WARNING: If your project creates custom `CacheManager` beans, it will either need to be marked with `@Primary` or injected using `@Qualifier`. + + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/removejsonattributesresponsebody-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/removejsonattributesresponsebody-factory.adoc new file mode 100644 index 00000000..4a458b21 --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/removejsonattributesresponsebody-factory.adoc @@ -0,0 +1,46 @@ +[[removejsonattributesresponsebody-gatewayfilter-factory]] += `RemoveJsonAttributesResponseBody` `GatewayFilter` Factory + +The `RemoveJsonAttributesResponseBody` `GatewayFilter` factory takes a collection of `attribute names` to search for, an optional last parameter from the list can be a boolean to remove the attributes just at root level (that's the default value if not present at the end of the parameter configuration, `false`) or recursively (`true`). +It provides a convenient method to apply a transformation to JSON body content by deleting attributes from it. + +The following example configures an `RemoveJsonAttributesResponseBody` `GatewayFilter`: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: removejsonattributes_route + uri: https://example.org + filters: + - RemoveJsonAttributesResponseBody=id,color +---- +==== + +This removes attributes "id" and "color" from the JSON content body at root level. + +The following example configures an `RemoveJsonAttributesResponseBody` `GatewayFilter` that uses the optional last parameter: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: removejsonattributes_recursively_route + uri: https://example.org + predicates: + - Path=/red/{segment} + filters: + - RemoveJsonAttributesResponseBody=id,color,true +---- +==== + +This removes attributes "id" and "color" from the JSON content body at any level. + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-addrequestheader-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-addrequestheader-factory.adoc new file mode 100644 index 00000000..4537e209 --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-addrequestheader-factory.adoc @@ -0,0 +1,44 @@ +[[the-addrequestheader-gatewayfilter-factory]] += The `AddRequestHeader` `GatewayFilter` Factory + +The `AddRequestHeader` `GatewayFilter` factory takes a `name` and `value` parameter. +The following example configures an `AddRequestHeader` `GatewayFilter`: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: add_request_header_route + uri: https://example.org + filters: + - AddRequestHeader=X-Request-red, blue +---- +==== + +This listing adds `X-Request-red:blue` header to the downstream request's headers for all matching requests. + +`AddRequestHeader` is aware of the URI variables used to match a path or host. +URI variables may be used in the value and are expanded at runtime. +The following example configures an `AddRequestHeader` `GatewayFilter` that uses a variable: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: add_request_header_route + uri: https://example.org + predicates: + - Path=/red/{segment} + filters: + - AddRequestHeader=X-Request-Red, Blue-{segment} +---- +==== + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-addrequestheadersifnotpresent-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-addrequestheadersifnotpresent-factory.adoc new file mode 100644 index 00000000..f5a8c95d --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-addrequestheadersifnotpresent-factory.adoc @@ -0,0 +1,48 @@ +[[the-addrequestheadersifnotpresent-gatewayfilter-factory]] += The `AddRequestHeadersIfNotPresent` `GatewayFilter` Factory + +The `AddRequestHeadersIfNotPresent` `GatewayFilter` factory takes a collection of `name` and `value` pairs separated by colon. +The following example configures an `AddRequestHeadersIfNotPresent` `GatewayFilter`: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: add_request_headers_route + uri: https://example.org + filters: + - AddRequestHeadersIfNotPresent=X-Request-Color-1:blue,X-Request-Color-2:green +---- +==== + +This listing adds 2 headers `X-Request-Color-1:blue` and `X-Request-Color-2:green` to the downstream request's headers for all matching requests. +This is similar to how `AddRequestHeader` works, but unlike `AddRequestHeader` it will do it only if the header is not already there. +Otherwise, the original value in the client request is sent. + +Additionally, to set a multi-valued header, use the header name multiple times like `AddRequestHeadersIfNotPresent=X-Request-Color-1:blue,X-Request-Color-1:green`. + +`AddRequestHeadersIfNotPresent` also supports URI variables used to match a path or host. +URI variables may be used in the value and are expanded at runtime. +The following example configures an `AddRequestHeadersIfNotPresent` `GatewayFilter` that uses a variable: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: add_request_header_route + uri: https://example.org + predicates: + - Path=/red/{segment} + filters: + - AddRequestHeadersIfNotPresent=X-Request-Red:Blue-{segment} +---- +==== + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-addrequestparameter-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-addrequestparameter-factory.adoc new file mode 100644 index 00000000..a481da0a --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-addrequestparameter-factory.adoc @@ -0,0 +1,44 @@ +[[the-addrequestparameter-gatewayfilter-factory]] += The `AddRequestParameter` `GatewayFilter` Factory + +The `AddRequestParameter` `GatewayFilter` Factory takes a `name` and `value` parameter. +The following example configures an `AddRequestParameter` `GatewayFilter`: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: add_request_parameter_route + uri: https://example.org + filters: + - AddRequestParameter=red, blue +---- +==== + +This will add `red=blue` to the downstream request's query string for all matching requests. + +`AddRequestParameter` is aware of the URI variables used to match a path or host. +URI variables may be used in the value and are expanded at runtime. +The following example configures an `AddRequestParameter` `GatewayFilter` that uses a variable: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: add_request_parameter_route + uri: https://example.org + predicates: + - Host: {segment}.myhost.org + filters: + - AddRequestParameter=foo, bar-{segment} +---- +==== + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-addresponseheader-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-addresponseheader-factory.adoc new file mode 100644 index 00000000..6e38f6e2 --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-addresponseheader-factory.adoc @@ -0,0 +1,45 @@ +[[the-addresponseheader-gatewayfilter-factory]] += The `AddResponseHeader` `GatewayFilter` Factory + +The `AddResponseHeader` `GatewayFilter` Factory takes a `name` and `value` parameter. +The following example configures an `AddResponseHeader` `GatewayFilter`: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: add_response_header_route + uri: https://example.org + filters: + - AddResponseHeader=X-Response-Red, Blue +---- +==== + +This adds `X-Response-Red:Blue` header to the downstream response's headers for all matching requests. + +`AddResponseHeader` is aware of URI variables used to match a path or host. +URI variables may be used in the value and are expanded at runtime. +The following example configures an `AddResponseHeader` `GatewayFilter` that uses a variable: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: add_response_header_route + uri: https://example.org + predicates: + - Host: {segment}.myhost.org + filters: + - AddResponseHeader=foo, bar-{segment} +---- +==== + + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-cacherequestbody-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-cacherequestbody-factory.adoc new file mode 100644 index 00000000..020f5188 --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-cacherequestbody-factory.adoc @@ -0,0 +1,46 @@ +[[the-cacherequestbody-gatewayfilter-factory]] += The `CacheRequestBody` `GatewayFilter` Factory + +Some situations necessitate reading the request body. Since the request can be read only once, we need to cache the request body. +You can use the `CacheRequestBody` filter to cache the request body before sending it downstream and getting the body from `exchange` attribute. + +The following listing shows how to cache the request body `GatewayFilter`: + +==== +[source,java] +---- +@Bean +public RouteLocator routes(RouteLocatorBuilder builder) { + return builder.routes() + .route("cache_request_body_route", r -> r.path("/downstream/**") + .filters(f -> f.prefixPath("/httpbin") + .cacheRequestBody(String.class).uri(uri)) + .build(); +} +---- +==== + + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: cache_request_body_route + uri: lb://downstream + predicates: + - Path=/downstream/** + filters: + - name: CacheRequestBody + args: + bodyClass: java.lang.String +---- +==== +`CacheRequestBody` extracts the request body and converts it to a body class (such as `java.lang.String`, defined in the preceding example). +`CacheRequestBody` then places it in the attributes available from `ServerWebExchange.getAttributes()`, with a key defined in `ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR`. + +NOTE: This filter works only with HTTP (including HTTPS) requests. + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-deduperesponseheader-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-deduperesponseheader-factory.adoc new file mode 100644 index 00000000..d3bc2f57 --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-deduperesponseheader-factory.adoc @@ -0,0 +1,27 @@ +[[the-deduperesponseheader-gatewayfilter-factory]] += The `DedupeResponseHeader` `GatewayFilter` Factory + +The `DedupeResponseHeader` GatewayFilter factory takes a `name` parameter and an optional `strategy` parameter. `name` can contain a space-separated list of header names. +The following example configures a `DedupeResponseHeader` `GatewayFilter`: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: dedupe_response_header_route + uri: https://example.org + filters: + - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin +---- +==== + +This removes duplicate values of `Access-Control-Allow-Credentials` and `Access-Control-Allow-Origin` response headers in cases when both the gateway CORS logic and the downstream logic add them. + +The `DedupeResponseHeader` filter also accepts an optional `strategy` parameter. +The accepted values are `RETAIN_FIRST` (default), `RETAIN_LAST`, and `RETAIN_UNIQUE`. + + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-jsontogrpc-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-jsontogrpc-factory.adoc new file mode 100644 index 00000000..c956f6d3 --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-jsontogrpc-factory.adoc @@ -0,0 +1,80 @@ +[[the-jsontogrpc-gatewayfilter-factory]] += The `JsonToGrpc` `GatewayFilter` Factory + +The JSONToGRPCFilter GatewayFilter Factory converts a JSON payload to a gRPC request. + +The filter takes the following arguments: + +* `protoDescriptor`: Proto descriptor file. + +This file can be generated using `protoc` and specifying the `--descriptor_set_out` flag: + +[source,bash] +---- +protoc --proto_path=src/main/resources/proto/ \ +--descriptor_set_out=src/main/resources/proto/hello.pb \ +src/main/resources/proto/hello.proto +---- + +* `protoFile`: Proto definition file. + +* `service`: Short name of the service that handles the request. + +* `method`: Method name in the service that handles the request. + +NOTE: `streaming` is not supported. + + +*application.yml.* + +[source,java] +---- +@Bean +public RouteLocator routes(RouteLocatorBuilder builder) { + return builder.routes() + .route("json-grpc", r -> r.path("/json/hello").filters(f -> { + String protoDescriptor = "file:src/main/proto/hello.pb"; + String protoFile = "file:src/main/proto/hello.proto"; + String service = "HelloService"; + String method = "hello"; + return f.jsonToGRPC(protoDescriptor, protoFile, service, method); + }).uri(uri)) +---- + +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: json-grpc + uri: https://localhost:6565/testhello + predicates: + - Path=/json/** + filters: + - name: JsonToGrpc + args: + protoDescriptor: file:proto/hello.pb + protoFile: file:proto/hello.proto + service: HelloService + method: hello + +---- + +When a request is made through the gateway to `/json/hello`, the request is transformed by using the definition provided in `hello.proto`, sent to `HelloService/hello`, and the response back is transformed to JSON. + +By default, it creates a `NettyChannel` by using the default `TrustManagerFactory`. However, you can customize this `TrustManager` by creating a bean of type `GrpcSslConfigurer`: + +[source,java] +---- + +@Configuration +public class GRPCLocalConfiguration { + @Bean + public GRPCSSLContext sslContext() { + TrustManager trustManager = trustAllCerts(); + return new GRPCSSLContext(trustManager); + } +} +---- + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-maprequestheader-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-maprequestheader-factory.adoc new file mode 100644 index 00000000..94de7ab0 --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-maprequestheader-factory.adoc @@ -0,0 +1,26 @@ +[[the-maprequestheader-gatewayfilter-factory]] += The `MapRequestHeader` `GatewayFilter` Factory + +The `MapRequestHeader` `GatewayFilter` factory takes `fromHeader` and `toHeader` parameters. +It creates a new named header (`toHeader`), and the value is extracted out of an existing named header (`fromHeader`) from the incoming http request. +If the input header does not exist, the filter has no impact. +If the new named header already exists, its values are augmented with the new values. +The following example configures a `MapRequestHeader`: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: map_request_header_route + uri: https://example.org + filters: + - MapRequestHeader=Blue, X-Request-Red +---- +==== + +This adds the `X-Request-Red:` header to the downstream request with updated values from the incoming HTTP request's `Blue` header. + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-modifyrequestbody-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-modifyrequestbody-factory.adoc new file mode 100644 index 00000000..3d90cecd --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-modifyrequestbody-factory.adoc @@ -0,0 +1,46 @@ +[[the-modifyrequestbody-gatewayfilter-factory]] += The `ModifyRequestBody` `GatewayFilter` Factory + +You can use the `ModifyRequestBody` filter to modify the request body before it is sent downstream by the gateway. + +NOTE: This filter can be configured only by using the Java DSL. + +The following listing shows how to modify a request body `GatewayFilter`: + +==== +[source,java] +---- +@Bean +public RouteLocator routes(RouteLocatorBuilder builder) { + return builder.routes() + .route("rewrite_request_obj", r -> r.host("*.rewriterequestobj.org") + .filters(f -> f.prefixPath("/httpbin") + .modifyRequestBody(String.class, Hello.class, MediaType.APPLICATION_JSON_VALUE, + (exchange, s) -> Mono.just(new Hello(s.toUpperCase())))).uri(uri)) + .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; + } +} +---- + +NOTE: If the request has no body, the `RewriteFilter` is passed `null`. `Mono.empty()` should be returned to assign a missing body in the request. + +==== + + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-modifyresponsebody-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-modifyresponsebody-factory.adoc new file mode 100644 index 00000000..dbf18568 --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-modifyresponsebody-factory.adoc @@ -0,0 +1,26 @@ +[[the-modifyresponsebody-gatewayfilter-factory]] += The `ModifyResponseBody` `GatewayFilter` Factory + +You can use the `ModifyResponseBody` filter to modify the response body before it is sent back to the client. + +NOTE: This filter can be configured only by using the Java DSL. + +The following listing shows how to modify a response body `GatewayFilter`: + +==== +[source,java] +---- +@Bean +public RouteLocator routes(RouteLocatorBuilder builder) { + return builder.routes() + .route("rewrite_response_upper", r -> r.host("*.rewriteresponseupper.org") + .filters(f -> f.prefixPath("/httpbin") + .modifyResponseBody(String.class, String.class, + (exchange, s) -> Mono.just(s.toUpperCase()))).uri(uri)) + .build(); +} +---- + +NOTE: If the response has no body, the `RewriteFilter` is passed `null`. `Mono.empty()` should be returned to assign a missing body in the response. +==== + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-prefixpath-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-prefixpath-factory.adoc new file mode 100644 index 00000000..14bc87cf --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-prefixpath-factory.adoc @@ -0,0 +1,24 @@ +[[the-prefixpath-gatewayfilter-factory]] += The `PrefixPath` `GatewayFilter` Factory + +The `PrefixPath` `GatewayFilter` factory takes a single `prefix` parameter. +The following example configures a `PrefixPath` `GatewayFilter`: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: prefixpath_route + uri: https://example.org + filters: + - PrefixPath=/mypath +---- +==== + +This prefixes `/mypath` to the path of all matching requests. +So a request to `/hello` is sent to `/mypath/hello`. + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-preservehostheader-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-preservehostheader-factory.adoc new file mode 100644 index 00000000..0cbe1a0f --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-preservehostheader-factory.adoc @@ -0,0 +1,22 @@ +[[the-preservehostheader-gatewayfilter-factory]] += The `PreserveHostHeader` `GatewayFilter` Factory + +The `PreserveHostHeader` `GatewayFilter` factory has no parameters. +This filter sets a request attribute that the routing filter inspects to determine if the original host header should be sent rather than the host header determined by the HTTP client. +The following example configures a `PreserveHostHeader` `GatewayFilter`: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: preserve_host_route + uri: https://example.org + filters: + - PreserveHostHeader +---- +==== + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-redirectto-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-redirectto-factory.adoc new file mode 100644 index 00000000..ab9136dd --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-redirectto-factory.adoc @@ -0,0 +1,28 @@ +[[the-redirectto-gatewayfilter-factory]] += The `RedirectTo` `GatewayFilter` Factory + +The `RedirectTo` `GatewayFilter` factory takes two parameters, `status` and `url`. +The `status` parameter should be a 300 series redirect HTTP code, such as 301. +The `url` parameter should be a valid URL. +This is the value of the `Location` header. +For relative redirects, you should use `uri: no://op` as the uri of your route definition. +The following listing configures a `RedirectTo` `GatewayFilter`: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: prefixpath_route + uri: https://example.org + filters: + - RedirectTo=302, https://acme.org +---- +==== + +This will send a status 302 with a `Location:https://acme.org` header to perform a redirect. + + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-removerequestheader-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-removerequestheader-factory.adoc new file mode 100644 index 00000000..c1fafbfb --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-removerequestheader-factory.adoc @@ -0,0 +1,24 @@ +[[the-removerequestheader-gatewayfilter-factory]] += The `RemoveRequestHeader` GatewayFilter Factory + +The `RemoveRequestHeader` `GatewayFilter` factory takes a `name` parameter. +It is the name of the header to be removed. +The following listing configures a `RemoveRequestHeader` `GatewayFilter`: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: removerequestheader_route + uri: https://example.org + filters: + - RemoveRequestHeader=X-Request-Foo +---- +==== + +This removes the `X-Request-Foo` header before it is sent downstream. + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-removerequestparameter-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-removerequestparameter-factory.adoc new file mode 100644 index 00000000..6b155ddd --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-removerequestparameter-factory.adoc @@ -0,0 +1,25 @@ +[[the-removerequestparameter-gatewayfilter-factory]] += The `RemoveRequestParameter` `GatewayFilter` Factory + +The `RemoveRequestParameter` `GatewayFilter` factory takes a `name` parameter. +It is the name of the query parameter to be removed. +The following example configures a `RemoveRequestParameter` `GatewayFilter`: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: removerequestparameter_route + uri: https://example.org + filters: + - RemoveRequestParameter=red +---- +==== + +This will remove the `red` parameter before it is sent downstream. + + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-removeresponseheader-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-removeresponseheader-factory.adoc new file mode 100644 index 00000000..45b460fd --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-removeresponseheader-factory.adoc @@ -0,0 +1,28 @@ +[[the-removeresponseheader-gatewayfilter-factory]] += The `RemoveResponseHeader` `GatewayFilter` Factory + +The `RemoveResponseHeader` `GatewayFilter` factory takes a `name` parameter. +It is the name of the header to be removed. +The following listing configures a `RemoveResponseHeader` `GatewayFilter`: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: removeresponseheader_route + uri: https://example.org + filters: + - RemoveResponseHeader=X-Response-Foo +---- +==== + +This will remove the `X-Response-Foo` header from the response before it is returned to the gateway client. + +To remove any kind of sensitive header, you should configure this filter for any routes for which you may want to do so. +In addition, you can configure this filter once by using `spring.cloud.gateway.default-filters` and have it applied to all routes. + + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-requestheadersize-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-requestheadersize-factory.adoc new file mode 100644 index 00000000..d47d1383 --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-requestheadersize-factory.adoc @@ -0,0 +1,24 @@ +[[the-requestheadersize-gatewayfilter-factory]] += The `RequestHeaderSize` `GatewayFilter` Factory + +The `RequestHeaderSize` `GatewayFilter` factory takes `maxSize` and `errorHeaderName` parameters. +The `maxSize` parameter is the maximum data size allowed by the request header (including key and value). The `errorHeaderName` parameter sets the name of the response header containing an error message, by default it is "errorMessage". +The following listing configures a `RequestHeaderSize` `GatewayFilter`: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: requestheadersize_route + uri: https://example.org + filters: + - RequestHeaderSize=1000B +---- +==== + +This will send a status 431 if size of any request header is greater than 1000 Bytes. + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-requestratelimiter-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-requestratelimiter-factory.adoc new file mode 100644 index 00000000..8d72465e --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-requestratelimiter-factory.adoc @@ -0,0 +1,130 @@ +[[the-requestratelimiter-gatewayfilter-factory]] += The `RequestRateLimiter` `GatewayFilter` Factory + +The `RequestRateLimiter` `GatewayFilter` factory uses a `RateLimiter` implementation to determine if the current request is allowed to proceed. If it is not, a status of `HTTP 429 - Too Many Requests` (by default) is returned. + +This filter takes an optional `keyResolver` parameter and parameters specific to the rate limiter (described <>). + +`keyResolver` is a bean that implements the `KeyResolver` interface. +In configuration, reference the bean by name using SpEL. +`#{@myKeyResolver}` is a SpEL expression that references a bean named `myKeyResolver`. +The following listing shows the `KeyResolver` interface: + +.KeyResolver.java +==== +[source,java] +---- +public interface KeyResolver { + Mono resolve(ServerWebExchange exchange); +} +---- +==== + +[[key-resolver-section]] +The `KeyResolver` interface lets pluggable strategies derive the key for limiting requests. +In future milestone releases, there will be some `KeyResolver` implementations. + +The default implementation of `KeyResolver` is the `PrincipalNameKeyResolver`, which retrieves the `Principal` from the `ServerWebExchange` and calls `Principal.getName()`. + +By default, if the `KeyResolver` does not find a key, requests are denied. +You can adjust this behavior by setting the `spring.cloud.gateway.filter.request-rate-limiter.deny-empty-key` (`true` or `false`) and `spring.cloud.gateway.filter.request-rate-limiter.empty-key-status-code` properties. + +[NOTE] +===== +The `RequestRateLimiter` is not configurable with the "shortcut" notation. The following example below is _invalid_: + +.application.properties +==== +---- +# INVALID SHORTCUT CONFIGURATION +spring.cloud.gateway.routes[0].filters[0]=RequestRateLimiter=2, 2, #{@userkeyresolver} +---- +==== +===== + +[[the-redis-ratelimiter]] +== The Redis `RateLimiter` + +The Redis implementation is based on work done at https://stripe.com/blog/rate-limiters[Stripe]. +It requires the use of the `spring-boot-starter-data-redis-reactive` Spring Boot starter. + +The algorithm used is the https://en.wikipedia.org/wiki/Token_bucket[Token Bucket Algorithm]. + +The `redis-rate-limiter.replenishRate` property defines how many requests per second to allow (without any dropped requests). +This is the rate at which the token bucket is filled. + +The `redis-rate-limiter.burstCapacity` property is the maximum number of requests a user is allowed in a single second (without any dropped requests). +This is the number of tokens the token bucket can hold. +Setting this value to zero blocks all requests. + +The `redis-rate-limiter.requestedTokens` property is how many tokens a request costs. +This is the number of tokens taken from the bucket for each request and defaults to `1`. + +A steady rate is accomplished by setting the same value in `replenishRate` and `burstCapacity`. +Temporary bursts can be allowed by setting `burstCapacity` higher than `replenishRate`. +In this case, the rate limiter needs to be allowed some time between bursts (according to `replenishRate`), as two consecutive bursts results in dropped requests (`HTTP 429 - Too Many Requests`). +The following listing configures a `redis-rate-limiter`: + +Rate limits below `1 request/s` are accomplished by setting `replenishRate` to the wanted number of requests, `requestedTokens` to the timespan in seconds, and `burstCapacity` to the product of `replenishRate` and `requestedTokens`. +For example, setting `replenishRate=1`, `requestedTokens=60`, and `burstCapacity=60` results in a limit of `1 request/min`. +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: requestratelimiter_route + uri: https://example.org + filters: + - name: RequestRateLimiter + args: + redis-rate-limiter.replenishRate: 10 + redis-rate-limiter.burstCapacity: 20 + redis-rate-limiter.requestedTokens: 1 + +---- +==== + +The following example configures a `KeyResolver` in Java: + +.Config.java +==== +[source,java] +---- +@Bean +KeyResolver userKeyResolver() { + return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user")); +} +---- +==== + +This defines a request rate limit of 10 per user. A burst of 20 is allowed, but, in the next second, only 10 requests are available. +The `KeyResolver` is a simple one that gets the `user` request parameter +NOTE: This is not recommended for production + +You can also define a rate limiter as a bean that implements the `RateLimiter` interface. +In configuration, you can reference the bean by name using SpEL. +`#{@myRateLimiter}` is a SpEL expression that references a bean with named `myRateLimiter`. +The following listing defines a rate limiter that uses the `KeyResolver` defined in the previous listing: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: requestratelimiter_route + uri: https://example.org + filters: + - name: RequestRateLimiter + args: + rate-limiter: "#{@myRateLimiter}" + key-resolver: "#{@userKeyResolver}" + +---- +==== + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-requestsize-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-requestsize-factory.adoc new file mode 100644 index 00000000..e4e0e60b --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-requestsize-factory.adoc @@ -0,0 +1,39 @@ +[[the-requestsize-gatewayfilter-factory]] += The `RequestSize` `GatewayFilter` Factory + +When the request size is greater than the permissible limit, the `RequestSize` `GatewayFilter` factory can restrict a request from reaching the downstream service. +The filter takes a `maxSize` parameter. +The `maxSize` is a `DataSize` type, so values can be defined as a number followed by an optional `DataUnit` suffix such as 'KB' or 'MB'. The default is 'B' for bytes. +It is the permissible size limit of the request defined in bytes. +The following listing configures a `RequestSize` `GatewayFilter`: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: request_size_route + uri: http://localhost:8080/upload + predicates: + - Path=/upload + filters: + - name: RequestSize + args: + maxSize: 5000000 +---- +==== + +The `RequestSize` `GatewayFilter` factory sets the response status as `413 Payload Too Large` with an additional header `errorMessage` when the request is rejected due to size. The following example shows such an `errorMessage`: + +==== +[source] +---- +errorMessage : Request size is larger than permissible limit. Request size is 6.0 MB where permissible limit is 5.0 MB +---- +==== + +NOTE: The default request size is set to five MB if not provided as a filter argument in the route definition. + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-retry-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-retry-factory.adoc new file mode 100644 index 00000000..453e28be --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-retry-factory.adoc @@ -0,0 +1,90 @@ +[[the-retry-gatewayfilter-factory]] += The `Retry` `GatewayFilter` Factory + +The `Retry` `GatewayFilter` factory supports the following parameters: + +* `retries`: The number of retries that should be attempted. +* `statuses`: The HTTP status codes that should be retried, represented by using `org.springframework.http.HttpStatus`. +* `methods`: The HTTP methods that should be retried, represented by using `org.springframework.http.HttpMethod`. +* `series`: The series of status codes to be retried, represented by using `org.springframework.http.HttpStatus.Series`. +* `exceptions`: A list of thrown exceptions that should be retried. +* `backoff`: The configured exponential backoff for the retries. +Retries are performed after a backoff interval of `firstBackoff * (factor ^ n)`, where `n` is the iteration. +If `maxBackoff` is configured, the maximum backoff applied is limited to `maxBackoff`. +If `basedOnPreviousValue` is true, the backoff is calculated by using `prevBackoff * factor`. + +The following defaults are configured for `Retry` filter, if enabled: + +* `retries`: Three times +* `series`: 5XX series +* `methods`: GET method +* `exceptions`: `IOException` and `TimeoutException` +* `backoff`: disabled + +The following listing configures a Retry `GatewayFilter`: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: retry_test + uri: http://localhost:8080/flakey + predicates: + - Host=*.retry.com + filters: + - name: Retry + args: + retries: 3 + statuses: BAD_GATEWAY + methods: GET,POST + backoff: + firstBackoff: 10ms + maxBackoff: 50ms + factor: 2 + basedOnPreviousValue: false +---- +==== + +NOTE: When using the retry filter with a `forward:` prefixed URL, the target endpoint should be written carefully so that, in case of an error, it does not do anything that could result in a response being sent to the client and committed. +For example, if the target endpoint is an annotated controller, the target controller method should not return `ResponseEntity` with an error status code. +Instead, it should throw an `Exception` or signal an error (for example, through a `Mono.error(ex)` return value), which the retry filter can be configured to handle by retrying. + +WARNING: When using the retry filter with any HTTP method with a body, the body will be cached and the gateway will become memory constrained. The body is cached in a request attribute defined by `ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR`. The type of the object is `org.springframework.core.io.buffer.DataBuffer`. + +A simplified "shortcut" notation can be added with a single `status` and `method`. + +The following two examples are equivalent: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: retry_route + uri: https://example.org + filters: + - name: Retry + args: + retries: 3 + statuses: INTERNAL_SERVER_ERROR + methods: GET + backoff: + firstBackoff: 10ms + maxBackoff: 50ms + factor: 2 + basedOnPreviousValue: false + + - id: retryshortcut_route + uri: https://example.org + filters: + - Retry=3,INTERNAL_SERVER_ERROR,GET,10ms,50ms,2,false +---- +==== + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-rewritelocationresponseheader-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-rewritelocationresponseheader-factory.adoc new file mode 100644 index 00000000..f3b555b1 --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-rewritelocationresponseheader-factory.adoc @@ -0,0 +1,37 @@ +[[the-rewritelocationresponseheader-gatewayfilter-factory]] += The `RewriteLocationResponseHeader` `GatewayFilter` Factory + +The `RewriteLocationResponseHeader` `GatewayFilter` factory modifies the value of the `Location` response header, usually to get rid of backend-specific details. +It takes the `stripVersionMode`, `locationHeaderName`, `hostValue`, and `protocolsRegex` parameters. +The following listing configures a `RewriteLocationResponseHeader` `GatewayFilter`: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: rewritelocationresponseheader_route + uri: http://example.org + filters: + - RewriteLocationResponseHeader=AS_IN_REQUEST, Location, , +---- +==== + +For example, for a request of `POST https://api.example.com/some/object/name`, the `Location` response header value of `https://object-service.prod.example.net/v2/some/object/id` is rewritten as `https://api.example.com/some/object/id`. + +The `stripVersionMode` parameter has the following possible values: `NEVER_STRIP`, `AS_IN_REQUEST` (default), and `ALWAYS_STRIP`. + +* `NEVER_STRIP`: The version is not stripped, even if the original request path contains no version. +* `AS_IN_REQUEST`: The version is stripped only if the original request path contains no version. +* `ALWAYS_STRIP`: The version is always stripped, even if the original request path contains version. + +The `hostValue` parameter, if provided, is used to replace the `host:port` portion of the response `Location` header. +If it is not provided, the value of the `Host` request header is used. + +The `protocolsRegex` parameter must be a valid regex `String`, against which the protocol name is matched. +If it is not matched, the filter does nothing. +The default is `http|https|ftp|ftps`. + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-rewritepath-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-rewritepath-factory.adoc new file mode 100644 index 00000000..0a0ba037 --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-rewritepath-factory.adoc @@ -0,0 +1,26 @@ +[[the-rewritepath-gatewayfilter-factory]] += The `RewritePath` `GatewayFilter` Factory + +The `RewritePath` `GatewayFilter` factory takes a path `regexp` parameter and a `replacement` parameter. +This uses Java regular expressions for a flexible way to rewrite the request path. +The following listing configures a `RewritePath` `GatewayFilter`: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: rewritepath_route + uri: https://example.org + predicates: + - Path=/red/** + filters: + - RewritePath=/red/?(?.*), /$\{segment} +---- +==== + +For a request path of `/red/blue`, this sets the path to `/blue` before making the downstream request. Note that the `$` should be replaced with `$\` because of the YAML specification. + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-rewriteresponseheader-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-rewriteresponseheader-factory.adoc new file mode 100644 index 00000000..d6a42e9e --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-rewriteresponseheader-factory.adoc @@ -0,0 +1,25 @@ +[[the-rewriteresponseheader-gatewayfilter-factory]] += The `RewriteResponseHeader` `GatewayFilter` Factory + +The `RewriteResponseHeader` `GatewayFilter` factory takes `name`, `regexp`, and `replacement` parameters. +It uses Java regular expressions for a flexible way to rewrite the response header value. +The following example configures a `RewriteResponseHeader` `GatewayFilter`: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: rewriteresponseheader_route + uri: https://example.org + filters: + - RewriteResponseHeader=X-Response-Red, , password=[^&]+, password=*** +---- +==== + +For a header value of `/42?user=ford&password=omg!what&flag=true`, it is set to `/42?user=ford&password=\***&flag=true` after making the downstream request. +You must use `$\` to mean `$` because of the YAML specification. + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-savesession-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-savesession-factory.adoc new file mode 100644 index 00000000..2ee65356 --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-savesession-factory.adoc @@ -0,0 +1,26 @@ +[[the-savesession-gatewayfilter-factory]] += The `SaveSession` `GatewayFilter` Factory + +The `SaveSession` `GatewayFilter` factory forces a `WebSession::save` operation _before_ forwarding the call downstream. +This is of particular use when using something like https://projects.spring.io/spring-session/[Spring Session] with a lazy data store, and you need to ensure the session state has been saved before making the forwarded call. +The following example configures a `SaveSession` `GatewayFilter`: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: save_session + uri: https://example.org + predicates: + - Path=/foo/** + filters: + - SaveSession +---- +==== + +If you integrate https://projects.spring.io/spring-security/[Spring Security] with Spring Session and want to ensure security details have been forwarded to the remote process, this is critical. + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-secureheaders-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-secureheaders-factory.adoc new file mode 100644 index 00000000..95d9f314 --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-secureheaders-factory.adoc @@ -0,0 +1,40 @@ +[[the-secureheaders-gatewayfilter-factory]] += The `SecureHeaders` `GatewayFilter` Factory + +The `SecureHeaders` `GatewayFilter` factory adds a number of headers to the response, per the recommendation made in https://blog.appcanary.com/2017/http-security-headers.html[this blog post]. + +The following headers (shown with their default values) are added: + +* `X-Xss-Protection:1 (mode=block`) +* `Strict-Transport-Security (max-age=631138519`) +* `X-Frame-Options (DENY)` +* `X-Content-Type-Options (nosniff)` +* `Referrer-Policy (no-referrer)` +* `Content-Security-Policy (default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src https:; style-src 'self' https: 'unsafe-inline)'` +* `X-Download-Options (noopen)` +* `X-Permitted-Cross-Domain-Policies (none)` + +To change the default values, set the appropriate property in the `spring.cloud.gateway.filter.secure-headers` namespace. +The following properties are available: + +* `xss-protection-header` +* `strict-transport-security` +* `frame-options` +* `content-type-options` +* `referrer-policy` +* `content-security-policy` +* `download-options` +* `permitted-cross-domain-policies` + +To disable the default values set the `spring.cloud.gateway.filter.secure-headers.disable` property with comma-separated values. +The following example shows how to do so: + +==== +[source] +---- +spring.cloud.gateway.filter.secure-headers.disable=x-frame-options,strict-transport-security +---- +==== + +NOTE: The lowercase full name of the secure header needs to be used to disable it.. + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-setpath-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-setpath-factory.adoc new file mode 100644 index 00000000..ff9efe5f --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-setpath-factory.adoc @@ -0,0 +1,28 @@ +[[the-setpath-gatewayfilter-factory]] += The `SetPath` `GatewayFilter` Factory + +The `SetPath` `GatewayFilter` factory takes a path `template` parameter. +It offers a simple way to manipulate the request path by allowing templated segments of the path. +This uses the URI templates from Spring Framework. +Multiple matching segments are allowed. +The following example configures a `SetPath` `GatewayFilter`: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: setpath_route + uri: https://example.org + predicates: + - Path=/red/{segment} + filters: + - SetPath=/{segment} +---- +==== + +For a request path of `/red/blue`, this sets the path to `/blue` before making the downstream request. + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-setrequestheader-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-setrequestheader-factory.adoc new file mode 100644 index 00000000..71fb5d2f --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-setrequestheader-factory.adoc @@ -0,0 +1,45 @@ +[[the-setrequestheader-gatewayfilter-factory]] += The `SetRequestHeader` `GatewayFilter` Factory + +The `SetRequestHeader` `GatewayFilter` factory takes `name` and `value` parameters. +The following listing configures a `SetRequestHeader` `GatewayFilter`: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: setrequestheader_route + uri: https://example.org + filters: + - SetRequestHeader=X-Request-Red, Blue +---- +==== + +This `GatewayFilter` replaces (rather than adding) all headers with the given name. +So, if the downstream server responded with `X-Request-Red:1234`, it will be replaced with `X-Request-Red:Blue`, which is what the downstream service would receive. + +`SetRequestHeader` is aware of URI variables used to match a path or host. +URI variables may be used in the value and are expanded at runtime. +The following example configures an `SetRequestHeader` `GatewayFilter` that uses a variable: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: setrequestheader_route + uri: https://example.org + predicates: + - Host: {segment}.myhost.org + filters: + - SetRequestHeader=foo, bar-{segment} +---- +==== + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-setrequesthostheader-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-setrequesthostheader-factory.adoc new file mode 100644 index 00000000..c58972e4 --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-setrequesthostheader-factory.adoc @@ -0,0 +1,29 @@ +[[the-setrequesthostheader-gatewayfilter-factory]] += The `SetRequestHostHeader` `GatewayFilter` Factory + +There are certain situation when the host header may need to be overridden. In this situation, the `SetRequestHostHeader` `GatewayFilter` factory can replace the existing host header with a specified value. +The filter takes a `host` parameter. +The following listing configures a `SetRequestHostHeader` `GatewayFilter`: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: set_request_host_header_route + uri: http://localhost:8080/headers + predicates: + - Path=/headers + filters: + - name: SetRequestHostHeader + args: + host: example.org +---- +==== + +The `SetRequestHostHeader` `GatewayFilter` factory replaces the value of the host header with `example.org`. + + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-setresponseheader-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-setresponseheader-factory.adoc new file mode 100644 index 00000000..3ce58bda --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-setresponseheader-factory.adoc @@ -0,0 +1,45 @@ +[[the-setresponseheader-gatewayfilter-factory]] += The `SetResponseHeader` `GatewayFilter` Factory + +The `SetResponseHeader` `GatewayFilter` factory takes `name` and `value` parameters. +The following listing configures a `SetResponseHeader` `GatewayFilter`: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: setresponseheader_route + uri: https://example.org + filters: + - SetResponseHeader=X-Response-Red, Blue +---- +==== + +This GatewayFilter replaces (rather than adding) all headers with the given name. +So, if the downstream server responded with `X-Response-Red:1234`, it will be replaced with `X-Response-Red:Blue`, which is what the gateway client would receive. + +`SetResponseHeader` is aware of URI variables used to match a path or host. +URI variables may be used in the value and will be expanded at runtime. +The following example configures an `SetResponseHeader` `GatewayFilter` that uses a variable: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: setresponseheader_route + uri: https://example.org + predicates: + - Host: {segment}.myhost.org + filters: + - SetResponseHeader=foo, bar-{segment} +---- +==== + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-setstatus-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-setstatus-factory.adoc new file mode 100644 index 00000000..e8ce4fa1 --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-setstatus-factory.adoc @@ -0,0 +1,44 @@ +[[the-setstatus-gatewayfilter-factory]] += The `SetStatus` `GatewayFilter` Factory + +The `SetStatus` `GatewayFilter` factory takes a single parameter, `status`. +It must be a valid Spring `HttpStatus`. +It may be the integer value `404` or the string representation of the enumeration: `NOT_FOUND`. +The following listing configures a `SetStatus` `GatewayFilter`: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: setstatusstring_route + uri: https://example.org + filters: + - SetStatus=UNAUTHORIZED + - id: setstatusint_route + uri: https://example.org + filters: + - SetStatus=401 +---- +==== + +In either case, the HTTP status of the response is set to 401. + +You can configure the `SetStatus` `GatewayFilter` to return the original HTTP status code from the proxied request in a header in the response. +The header is added to the response if configured with the following property: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + set-status: + original-status-header-name: original-http-status +---- +==== + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-stripprefix-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-stripprefix-factory.adoc new file mode 100644 index 00000000..e7ae996f --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-stripprefix-factory.adoc @@ -0,0 +1,26 @@ +[[the-stripprefix-gatewayfilter-factory]] += The `StripPrefix` `GatewayFilter` Factory + +The `StripPrefix` `GatewayFilter` factory takes one parameter, `parts`. +The `parts` parameter indicates the number of parts in the path to strip from the request before sending it downstream. +The following listing configures a `StripPrefix` `GatewayFilter`: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: nameRoot + uri: https://nameservice + predicates: + - Path=/name/** + filters: + - StripPrefix=2 +---- +==== + +When a request is made through the gateway to `/name/blue/red`, the request made to `nameservice` looks like `https://nameservice/red`. + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-tokenrelay-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-tokenrelay-factory.adoc new file mode 100644 index 00000000..e395c3df --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/the-tokenrelay-factory.adoc @@ -0,0 +1,103 @@ +[[the-tokenrelay-gatewayfilter-factory]] += The `TokenRelay` `GatewayFilter` Factory + +A Token Relay is where an OAuth2 consumer acts as a Client and +forwards the incoming token to outgoing resource requests. The +consumer can be a pure Client (like an SSO application) or a Resource +Server. + +Spring Cloud Gateway can forward OAuth2 access tokens downstream to the services +it is proxying using the `TokenRelay` `GatewayFilter`. + +The `TokenRelay` `GatewayFilter` takes one optional parameter, `clientRegistrationId`. +The following example configures a `TokenRelay` `GatewayFilter`: + +.App.java +[source,java] +---- + +@Bean +public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { + return builder.routes() + .route("resource", r -> r.path("/resource") + .filters(f -> f.tokenRelay("myregistrationid")) + .uri("http://localhost:9000")) + .build(); +} +---- + +or this + +.application.yaml +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: resource + uri: http://localhost:9000 + predicates: + - Path=/resource + filters: + - TokenRelay=myregistrationid +---- + +The example above specifies a `clientRegistrationId`, which can be used to obtain and forward an OAuth2 access token for any available `ClientRegistration`. + +Spring Cloud Gateway can also forward the OAuth2 access token of the currently authenticated user `oauth2Login()` is used to authenticate the user. +To add this functionality to the gateway, you can omit the `clientRegistrationId` parameter like this: + +.App.java +[source,java] +---- + +@Bean +public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { + return builder.routes() + .route("resource", r -> r.path("/resource") + .filters(f -> f.tokenRelay()) + .uri("http://localhost:9000")) + .build(); +} +---- + +or this + +.application.yaml +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: resource + uri: http://localhost:9000 + predicates: + - Path=/resource + filters: + - TokenRelay= +---- + +and it will (in addition to logging the user in and grabbing a token) +pass the authentication token downstream to the services (in this case +`/resource`). + +To enable this for Spring Cloud Gateway add the following dependencies + +- `org.springframework.boot:spring-boot-starter-oauth2-client` + +How does it work? The {github-code}/src/main/java/org/springframework/cloud/gateway/security/TokenRelayGatewayFilterFactory.java[filter] +extracts an OAuth2 access token from the currently authenticated user for the provided `clientRegistrationId`. +If no `clientRegistrationId` is provided, the currently authenticated user's own access token (obtained during login) is used. +In either case, the extracted access token is placed in a request header for the downstream requests. + +For a full working sample see https://github.com/spring-cloud-samples/sample-gateway-oauth2login[this project]. + +NOTE: A `TokenRelayGatewayFilterFactory` bean will only be created if the proper `spring.security.oauth2.client.*` properties are set which will trigger creation of a `ReactiveClientRegistrationRepository` bean. + +NOTE: The default implementation of `ReactiveOAuth2AuthorizedClientService` used by `TokenRelayGatewayFilterFactory` +uses an in-memory data store. You will need to provide your own implementation `ReactiveOAuth2AuthorizedClientService` +if you need a more robust solution. + + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/global-filters.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/global-filters.adoc new file mode 100644 index 00000000..801055fe --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/global-filters.adoc @@ -0,0 +1,206 @@ +[[global-filters]] += Global Filters + +The `GlobalFilter` interface has the same signature as `GatewayFilter`. +These are special filters that are conditionally applied to all routes. + +NOTE: This interface and its usage are subject to change in future milestone releases. + +[[gateway-combined-global-filter-and-gatewayfilter-ordering]] +== 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 <>), 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: + +.ExampleConfiguration.java +==== +[source,java] +---- +@Bean +public GlobalFilter customFilter() { + return new CustomGlobalFilter(); +} + +public class CustomGlobalFilter implements GlobalFilter, Ordered { + + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + log.info("custom global filter"); + return chain.filter(exchange); + } + + @Override + public int getOrder() { + return -1; + } +} +---- +==== + +[[the-gateway-metrics-filter]] +== 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 `spring.cloud.gateway.metrics.enabled` property is not set to `false`. +This filter adds a timer metric named `spring.cloud.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 link:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/HttpStatus.Series.html[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. + +In addition, through the `spring.cloud.gateway.metrics.tags.path.enabled` property (by default, `false`), you can activate an extra metric with the path tag: + +* `path`: The path of the request. + +These metrics are then available to be scraped from `/actuator/metrics/spring.cloud.gateway.requests` and can be easily integrated with Prometheus to create a link:images/gateway-grafana-dashboard.jpeg[Grafana] link:gateway-grafana-dashboard.json[dashboard]. + +NOTE: To enable the prometheus endpoint, add `micrometer-registry-prometheus` as a project dependency. + +[[local-cache-response-global-filter]] +== The Local Response Cache Filter + +The `LocalResponseCache` runs if associated properties are enabled: + +* `spring.cloud.gateway.global-filter.local-response-cache.enabled`: Activates the global cache for all routes +* `spring.cloud.gateway.filter.local-response-cache.enabled`: Activates the associated filter to use at route level + +This feature enables a local cache using Caffeine for all responses that meet the following criteria: + +* The request is a bodiless GET. +* The response has one of the following status codes: HTTP 200 (OK), HTTP 206 (Partial Content), or HTTP 301 (Moved Permanently). +* The HTTP `Cache-Control` header allows caching (that means it does not have any of the following values: `no-store` present in the request and `no-store` or `private` present in the response). + +It accepts two configuration parameters: + +* `spring.cloud.gateway.filter.local-response-cache.size`: Sets the maximum size of the cache to evict entries for this route (in KB, MB and GB). +* `spring.cloud.gateway.filter.local-response-cache.time-to-live` Sets the time to expire a cache entry (expressed in s for seconds, m for minutes, and h for hours). + +If none of these parameters are configured but the global filter is enabled, by default, it configures 5 minutes of time to live for the cached response. + +This filter also implements the automatic calculation of the `max-age` value in the HTTP `Cache-Control` header. +If `max-age` is present on the original response, the value is rewritten with the number of seconds set in the `timeToLive` configuration parameter. +In subsequent calls, this value is recalculated with the number of seconds left until the response expires. + +Setting `spring.cloud.gateway.global-filter.local-response-cache.enabled` to `false` deactivate the local response cache for all routes, the <> allows to use this functionality at route level. + +NOTE: To enable this feature, add `com.github.ben-manes.caffeine:caffeine` and `spring-boot-starter-cache` as project dependencies. + +WARNING: If your project creates custom `CacheManager` beans, it will either need to be marked with `@Primary` or injected using `@Qualifier`. + +[[forward-routing-filter]] +== 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. + +[[the-netty-routing-filter]] +== 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.) + +[[the-netty-write-response-filter]] +== 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.) + +[[reactive-loadbalancer-client-filter]] +== 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`: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: myRoute + uri: lb://service + predicates: + - Path=/service/** +---- +==== + +NOTE: 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`. + +NOTE: 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. + +TIP: Gateway supports all the LoadBalancer features. You can read more about them in the https://docs.spring.io/spring-cloud-commons/docs/current/reference/html/#spring-cloud-loadbalancer[Spring Cloud Commons documentation]. + +[[the-routetorequesturl-filter]] +== 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. + +If the URI has a scheme prefix, such as `lb:ws://serviceid`, the `lb` scheme is stripped from the URI and placed in the `ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR` for use later in the filter chain. + +[[the-websocket-routing-filter]] +== The Websocket Routing Filter + +If 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`. + +NOTE: If you use https://github.com/sockjs[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: + +.application.yml +==== +[source,yaml] +---- +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/** +---- +==== + +[[marking-an-exchange-as-routed]] +== 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 a `ServerWebExchange` object and checks if it has been "`routed`". +* `ServerWebExchangeUtils.setAlreadyRouted` takes a `ServerWebExchange` object and marks it as "`routed`". + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/glossary.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/glossary.adoc new file mode 100644 index 00000000..297b8af1 --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/glossary.adoc @@ -0,0 +1,10 @@ +[[glossary]] += Glossary + +* *Route*: The basic building block of the gateway. +It is defined by an ID, a destination URI, a collection of predicates, and a collection of filters. A route is matched if the aggregate predicate is true. +* *Predicate*: This is a https://docs.oracle.com/javase/8/docs/api/java/util/function/Predicate.html[Java 8 Function Predicate]. The input type is a https://docs.spring.io/spring/docs/5.0.x/javadoc-api/org/springframework/web/server/ServerWebExchange.html[Spring Framework `ServerWebExchange`]. +This lets you match on anything from the HTTP request, such as headers or parameters. +* *Filter*: These are instances of {github-code}/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/GatewayFilter.java[`GatewayFilter`] that have been constructed with a specific factory. +Here, you can modify requests and responses before or after sending the downstream request. + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/how-it-works.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/how-it-works.adoc new file mode 100644 index 00000000..2f883976 --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/how-it-works.adoc @@ -0,0 +1,14 @@ +[[gateway-how-it-works]] += How It Works + +The following diagram provides a high-level overview of how Spring Cloud Gateway works: + +image::spring_cloud_gateway_diagram.png[Spring Cloud Gateway Diagram] + +Clients make requests to Spring Cloud Gateway. If the Gateway Handler Mapping determines that a request matches a route, it is sent to the Gateway Web Handler. +This handler runs the request through a filter chain that is specific to the request. +The reason the filters are divided by the dotted line is that filters can run logic both before and after the proxy request is sent. +All "`pre`" filter logic is executed. Then the proxy request is made. After the proxy request is made, the "`post`" filter logic is run. + +NOTE: URIs defined in routes without a port get default port values of 80 and 443 for the HTTP and HTTPS URIs, respectively. + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/http-timeouts-configuration.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/http-timeouts-configuration.adoc new file mode 100644 index 00000000..4d1805a1 --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/http-timeouts-configuration.adoc @@ -0,0 +1,75 @@ +[[http-timeouts-configuration]] += Http timeouts configuration + +Http timeouts (response and connect) can be configured for all routes and overridden for each specific route. + +[[global-timeouts]] +== 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 +[source,yaml] +---- +spring: + cloud: + gateway: + httpclient: + connect-timeout: 1000 + response-timeout: 5s +---- + +[[per-route-timeouts]] +== 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 +[source,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 +[source,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(); + } +---- + +A per-route `response-timeout` with a negative value will disable the global `response-timeout` value. + +---- + - id: per_route_timeouts + uri: https://example.org + predicates: + - name: Path + args: + pattern: /delay/{timeout} + metadata: + response-timeout: -1 +---- + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/httpheadersfilters.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/httpheadersfilters.adoc new file mode 100644 index 00000000..e2a6ac82 --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/httpheadersfilters.adoc @@ -0,0 +1,45 @@ +[[httpheadersfilters]] += HttpHeadersFilters + +`HttpHeadersFilters` are applied to the requests before sending them downstream, such as in the `NettyRoutingFilter`. + +[[forwarded-headers-filter]] +== 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. + +[[removehopbyhop-headers-filter]] +== RemoveHopByHop Headers Filter +The `RemoveHopByHop` Headers Filter removes headers from forwarded requests. The default list of headers that is removed comes from the https://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-14#section-7.1.3[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. + +[[xforwarded-headers-filter]] +== XForwarded Headers Filter +The `XForwarded` Headers Filter creates various `X-Forwarded-*` headers to send to the downstream service. It uses 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` + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/reactor-netty-access-logs.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/reactor-netty-access-logs.adoc new file mode 100644 index 00000000..a9f071cd --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/reactor-netty-access-logs.adoc @@ -0,0 +1,29 @@ +[[reactor-netty-access-logs]] += Reactor Netty Access Logs + +To enable Reactor Netty access logs, set `-Dreactor.netty.http.server.accessLogEnabled=true`. + +IMPORTANT: 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: + +.logback.xml +==== +[source,xml] +---- + + access_log.log + + %msg%n + + + + + + + + + +---- +==== + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/request-predicates-factories.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/request-predicates-factories.adoc new file mode 100644 index 00000000..3f916ac6 --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/request-predicates-factories.adoc @@ -0,0 +1,406 @@ +[[gateway-request-predicates-factories]] += Route Predicate Factories + +Spring Cloud Gateway matches routes as part of the Spring WebFlux `HandlerMapping` infrastructure. +Spring Cloud Gateway includes many built-in route predicate factories. +All of these predicates match on different attributes of the HTTP request. +You can combine multiple route predicate factories with logical `and` statements. + +[[the-after-route-predicate-factory]] +== The After Route Predicate Factory + +The `After` route predicate factory takes one parameter, a `datetime` (which is a java `ZonedDateTime`). +This predicate matches requests that happen after the specified datetime. +The following example configures an after route predicate: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: after_route + uri: https://example.org + predicates: + - After=2017-01-20T17:42:47.789-07:00[America/Denver] +---- +==== + +This route matches any request made after Jan 20, 2017 17:42 Mountain Time (Denver). + +[[the-before-route-predicate-factory]] +== The Before Route Predicate Factory + +The `Before` route predicate factory takes one parameter, a `datetime` (which is a java `ZonedDateTime`). +This predicate matches requests that happen before the specified `datetime`. +The following example configures a before route predicate: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: before_route + uri: https://example.org + predicates: + - Before=2017-01-20T17:42:47.789-07:00[America/Denver] +---- +==== + +This route matches any request made before Jan 20, 2017 17:42 Mountain Time (Denver). + +[[the-between-route-predicate-factory]] +== The Between Route Predicate Factory + +The `Between` route predicate factory takes two parameters, `datetime1` and `datetime2` +which are java `ZonedDateTime` objects. +This predicate matches requests that happen after `datetime1` and before `datetime2`. +The `datetime2` parameter must be after `datetime1`. +The following example configures a between route predicate: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: between_route + uri: https://example.org + predicates: + - Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver] +---- +==== + +This route matches any request made after Jan 20, 2017 17:42 Mountain Time (Denver) and before Jan 21, 2017 17:42 Mountain Time (Denver). +This could be useful for maintenance windows. + +[[the-cookie-route-predicate-factory]] +== The Cookie Route Predicate Factory + +The `Cookie` route predicate factory takes two parameters, the cookie `name` and a `regexp` (which is a Java regular expression). +This predicate matches cookies that have the given name and whose values match the regular expression. +The following example configures a cookie route predicate factory: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: cookie_route + uri: https://example.org + predicates: + - Cookie=chocolate, ch.p +---- +==== + +This route matches requests that have a cookie named `chocolate` whose value matches the `ch.p` regular expression. + +[[the-header-route-predicate-factory]] +== The Header Route Predicate Factory + +The `Header` route predicate factory takes two parameters, the `header` and a `regexp` (which is a Java regular expression). +This predicate matches with a header that has the given name whose value matches the regular expression. +The following example configures a header route predicate: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: header_route + uri: https://example.org + predicates: + - Header=X-Request-Id, \d+ +---- +==== + +This route matches if the request has a header named `X-Request-Id` whose value matches the `\d+` regular expression (that is, it has a value of one or more digits). + +[[the-host-route-predicate-factory]] +== The Host Route Predicate Factory + +The `Host` route predicate factory takes one parameter: a list of host name `patterns`. +The pattern is an Ant-style pattern with `.` as the separator. +This predicates matches the `Host` header that matches the pattern. +The following example configures a host route predicate: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: host_route + uri: https://example.org + predicates: + - Host=**.somehost.org,**.anotherhost.org +---- +==== + +URI template variables (such as `{sub}.myhost.org`) are supported as well. + +This route matches if the request has a `Host` header with a value of `www.somehost.org` or `beta.somehost.org` or `www.anotherhost.org`. + +This predicate extracts the URI template variables (such as `sub`, defined in the preceding example) as a map of names and values and places it in the `ServerWebExchange.getAttributes()` with a key defined in `ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE`. +Those values are then available for use by <> + + +[[the-method-route-predicate-factory]] +== The Method Route Predicate Factory + +The `Method` Route Predicate Factory takes a `methods` argument which is one or more parameters: the HTTP methods to match. +The following example configures a method route predicate: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: method_route + uri: https://example.org + predicates: + - Method=GET,POST +---- +==== + +This route matches if the request method was a `GET` or a `POST`. + +[[the-path-route-predicate-factory]] +== The Path Route Predicate Factory + +The `Path` Route Predicate Factory takes two parameters: a list of Spring `PathMatcher` `patterns` and an optional flag called `matchTrailingSlash` (defaults to `true`). +The following example configures a path route predicate: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: path_route + uri: https://example.org + predicates: + - Path=/red/{segment},/blue/{segment} +---- +==== + +This route matches if the request path was, for example: `/red/1` or `/red/1/` or `/red/blue` or `/blue/green`. + +If `matchTrailingSlash` is set to `false`, then request path `/red/1/` will not be matched. + +This predicate extracts the URI template variables (such as `segment`, defined in the preceding example) as a map of names and values and places it in the `ServerWebExchange.getAttributes()` with a key defined in `ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE`. +Those values are then available for use by <> + +A utility method (called `get`) is available to make access to these variables easier. +The following example shows how to use the `get` method: + +==== +[source,java] +---- +Map uriVariables = ServerWebExchangeUtils.getUriTemplateVariables(exchange); + +String segment = uriVariables.get("segment"); +---- +==== + +[[the-query-route-predicate-factory]] +== The Query Route Predicate Factory + +The `Query` route predicate factory takes two parameters: a required `param` and an optional `regexp` (which is a Java regular expression). +The following example configures a query route predicate: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: query_route + uri: https://example.org + predicates: + - Query=green +---- +==== + +The preceding route matches if the request contained a `green` query parameter. + +.application.yml +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: query_route + uri: https://example.org + predicates: + - Query=red, gree. +---- + +The preceding route matches if the request contained a `red` query parameter whose value matched the `gree.` regexp, so `green` and `greet` would match. + + +[[the-remoteaddr-route-predicate-factory]] +== The RemoteAddr Route Predicate Factory + +The `RemoteAddr` route predicate factory takes a list (min size 1) of `sources`, which are CIDR-notation (IPv4 or IPv6) strings, such as `192.168.0.1/16` (where `192.168.0.1` is an IP address and `16` is a subnet mask). +The following example configures a RemoteAddr route predicate: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: remoteaddr_route + uri: https://example.org + predicates: + - RemoteAddr=192.168.1.1/24 +---- +==== + +This route matches if the remote address of the request was, for example, `192.168.1.10`. + +[[modifying-the-way-remote-addresses-are-resolved]] +=== Modifying the Way Remote Addresses Are Resolved + +By default, the RemoteAddr route predicate factory uses the remote address from the incoming request. +This may not match the actual client IP address if Spring Cloud Gateway sits behind a proxy layer. + +You can customize the way that the remote address is resolved by setting a custom `RemoteAddressResolver`. +Spring Cloud Gateway comes with one non-default remote address resolver that is based off of the https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For[X-Forwarded-For header], `XForwardedRemoteAddressResolver`. + +`XForwardedRemoteAddressResolver` has two static constructor methods, which take different approaches to security: + +* `XForwardedRemoteAddressResolver::trustAll` returns a `RemoteAddressResolver` that always takes the first IP address found in the `X-Forwarded-For` header. +This approach is vulnerable to spoofing, as a malicious client could set an initial value for the `X-Forwarded-For`, which would be accepted by the resolver. + +* `XForwardedRemoteAddressResolver::maxTrustedIndex` takes an index that correlates to the number of trusted infrastructure running in front of Spring Cloud Gateway. +If Spring Cloud Gateway is, for example only accessible through HAProxy, then a value of 1 should be used. +If two hops of trusted infrastructure are required before Spring Cloud Gateway is accessible, then a value of 2 should be used. + +Consider the following header value: + +==== +[source] +---- +X-Forwarded-For: 0.0.0.1, 0.0.0.2, 0.0.0.3 +---- +==== + +The following `maxTrustedIndex` values yield the following remote addresses: + +[options="header"] +|=== +|`maxTrustedIndex` | result +|[`Integer.MIN_VALUE`,0] | (invalid, `IllegalArgumentException` during initialization) +|1 | 0.0.0.3 +|2 | 0.0.0.2 +|3 | 0.0.0.1 +|[4, `Integer.MAX_VALUE`] | 0.0.0.1 +|=== +[[gateway-route-filters]] + +The following example shows how to achieve the same configuration with Java: + +.GatewayConfig.java +==== +[source,java] +---- +RemoteAddressResolver resolver = XForwardedRemoteAddressResolver + .maxTrustedIndex(1); + +... + +.route("direct-route", + r -> r.remoteAddr("10.1.1.1", "10.10.1.1/24") + .uri("https://downstream1") +.route("proxied-route", + r -> r.remoteAddr(resolver, "10.10.1.1", "10.10.1.1/24") + .uri("https://downstream2") +) +---- +==== + +[[the-weight-route-predicate-factory]] +== The Weight Route Predicate Factory + +The `Weight` route predicate factory takes two arguments: `group` and `weight` (an int). The weights are calculated per group. +The following example configures a weight route predicate: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: weight_high + uri: https://weighthigh.org + predicates: + - Weight=group1, 8 + - id: weight_low + uri: https://weightlow.org + predicates: + - Weight=group1, 2 +---- +==== + +This route would forward ~80% of traffic to https://weighthigh.org and ~20% of traffic to https://weighlow.org + +[[the-xforwarded-remote-addr-route-predicate-factory]] +== The XForwarded Remote Addr Route Predicate Factory + +The `XForwarded Remote Addr` route predicate factory takes a list (min size 1) of `sources`, which are CIDR-notation (IPv4 or IPv6) strings, such as `192.168.0.1/16` (where `192.168.0.1` is an IP address and `16` is a subnet mask). + +This route predicate allows requests to be filtered based on the `X-Forwarded-For` HTTP header. + +This can be used with reverse proxies such as load balancers or web application firewalls where +the request should only be allowed if it comes from a trusted list of IP addresses used by those +reverse proxies. + + +The following example configures a XForwardedRemoteAddr route predicate: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: xforwarded_remoteaddr_route + uri: https://example.org + predicates: + - XForwardedRemoteAddr=192.168.1.1/24 +---- +==== + +This route matches if the `X-Forwarded-For` header contains, for example, `192.168.1.10`. + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/route-metadata-configuration.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/route-metadata-configuration.adoc new file mode 100644 index 00000000..a447ad50 --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/route-metadata-configuration.adoc @@ -0,0 +1,36 @@ +[[route-metadata-configuration]] += Route Metadata Configuration + +You can configure additional parameters for each route by using metadata, as follows: + +.application.yml +==== +[source,yaml] +---- +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: + +==== +[source] +---- +Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR); +// get all metadata properties +route.getMetadata(); +// get a single metadata property +route.getMetadata(someKey); +---- +==== + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/starter.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/starter.adoc new file mode 100644 index 00000000..9b91af6f --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/starter.adoc @@ -0,0 +1,15 @@ +[[gateway-starter]] += How to Include Spring Cloud Gateway + +To include Spring Cloud Gateway in your project, use the starter with a group ID of `org.springframework.cloud` and an artifact ID of `spring-cloud-starter-gateway`. +See the https://projects.spring.io/spring-cloud/[Spring Cloud Project page] for details on setting up your build system with the current Spring Cloud Release Train. + +If you include the starter, but you do not want the gateway to be enabled, set `spring.cloud.gateway.enabled=false`. + +IMPORTANT: Spring Cloud Gateway is built on https://spring.io/projects/spring-boot#learn[Spring Boot], https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html[Spring WebFlux], and https://projectreactor.io/docs[Project Reactor]. +As a consequence, many of the familiar synchronous libraries (Spring Data and Spring Security, for example) and patterns you know may not apply when you use Spring Cloud Gateway. +If you are unfamiliar with these projects, we suggest you begin by reading their documentation to familiarize yourself with some new concepts before working with Spring Cloud Gateway. + +IMPORTANT: Spring Cloud Gateway requires the Netty runtime provided by Spring Boot and Spring Webflux. +It does not work in a traditional Servlet Container or when built as a WAR. + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/the-discoveryclient-route-definition-locator.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/the-discoveryclient-route-definition-locator.adoc new file mode 100644 index 00000000..6f0305ea --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/the-discoveryclient-route-definition-locator.adoc @@ -0,0 +1,38 @@ +[[the-discoveryclient-route-definition-locator]] += 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. + +[[configuring-predicates-and-filters-for-discoveryclient-routes]] +== 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/?(?.*)` 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: + +.application.properties +==== +[soure,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 + '/?(?.*)'" +spring.cloud.gateway.discovery.locator.filters[1].args[replacement]: "'/${remaining}'" +---- +==== + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/tls-and-ssl.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/tls-and-ssl.adoc new file mode 100644 index 00000000..802b4eb7 --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/tls-and-ssl.adoc @@ -0,0 +1,79 @@ +[[tls-and-ssl]] += 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: + +.application.yml +==== +[source,yaml] +---- +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: + +.application.yml +==== +[source,yaml] +---- +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: + +.application.yml +==== +[source,yaml] +---- +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). + +[[tls-handshake]] +== 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: + +.application.yml +==== +[source,yaml] +---- +spring: + cloud: + gateway: + httpclient: + ssl: + handshake-timeout-millis: 10000 + close-notify-flush-timeout-millis: 3000 + close-notify-read-timeout-millis: 0 +---- +==== + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/troubleshooting.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/troubleshooting.adoc new file mode 100644 index 00000000..6b3d333c --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/troubleshooting.adoc @@ -0,0 +1,24 @@ +[[troubleshooting]] += Troubleshooting + +This section covers common problems that may arise when you use Spring Cloud Gateway. + +[[log-levels]] +== 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` + +[[wiretap]] +== 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. +