The open-source Spring Cloud Gateway project includes a number of built-in filters for use in Gateway routes. The following commercial filters provided by Spring Cloud Gateway for VMware Tanzu can be used in addition to those included in the OSS project.

AllowedRequestCookieCount

This filter controls the maximum number of cookies allowed on a request. The filter will respond with a 431 Request Header Fields Too Large error if the number of cookies on a request exceeds the configured integer maximum.

In this example, only requests with two or fewer cookies will be accepted:

$ cf bind-service cook my-gateway -c '{ "routes": [ { "path": "/cook/**", "filters": ["AllowedRequestCookieCount=2"] } ] }'

AllowedRequestHeadersCount

This filter controls the maximum number of headers allowed on a request. The filter will respond with a 431 Request Header Fields Too Large error if the number of headers on a request exceeds the configured integer maximum.

In this example, only requests with four or fewer headers will be accepted:

$ cf bind-service cook my-gateway -c '{ "routes": [ { "path": "/cook/**", "filters": ["AllowedRequestHeadersCount=4"] } ] }'

AllowedRequestQueryParamsCount

This filter controls the maximum number of query parameters allowed on a request. The filter will respond with a 414 URL Too Large error if the number of query parameters on a request exceeds the configured integer maximum.

In this example, only requests with three or fewer query parameters will be accepted:

$ cf bind-service cook my-gateway -c '{ "routes": [ { "path": "/cook/**", "filters": ["AllowedRequestQueryParamsCount=3"] } ] }'

CircuitBreaker

The CircuitBreaker filter will reroute requests to a fallback destination when the intended destination responds with an HTTP error code.

The circuit breaker pattern is a useful approach to bolster resilience and prevent cascading failures in distributed systems. It works by preventing struggling services from becoming overloaded with failing requests, and thereby giving them chance to recover.

In electrical systems, a circuit breaker is a switch that triggers on a detected fault, isolating the faulty circuit and preventing further damage. This act is known as opening the circuit breaker (breaking the circuit). When the fault is corrected, the circuit breaker is closed (completing the circuit), allowing current to flow again. The circuit breaker pattern borrows this highly useful technique and terminology and applies it to distributed software systems.

Because our systems must be able to recover autonomously, there is also a half-open state which allows the circuit breaker to detect recovery of the downstream system. Following a timeout after the original detected failure, the circuit breaker will allow trial requests through to the destination system and then either fully close, or fully open and restart the timeout, based on the status of the response.

In the following example, the CircuitBreaker filter is used to cause requests to /cook/** to fall back to /inCaseOfFailureUseThis, should the service respond with an error code:

$ cf bind-service cook my-gateway -c '{ "routes": [ { "path": "/cook/**", "filters":["CircuitBreaker=myCircuitBreaker,forward:/inCaseOfFailureUseThis"] } ] }'

The CircuitBreaker filter supports several further options that can be appended to its configuration to fine tune its behavior:

  • A colon-separated list of HTTP status codes that will trigger the fallback behavior. These can be expressed in either numerical or text format:

    CircuitBreaker=myCircuitBreaker,forward:/inCaseOfFailureUseThis,401:NOT_FOUND:500
    
  • The percentage failure rate threshold above which the circuit breaker will be opened (default 50%, expressed as a float value):

    CircuitBreaker=myCircuitBreaker,forward:/inCaseOfFailureUseThis,401:NOT_FOUND:500,10
    
  • The period of time in seconds to wait for downstream service recovery before entering the 'half-open' state and attempting to close the circuit breaker again (default 60s).

    CircuitBreaker=myCircuitBreaker,forward:/inCaseOfFailureUseThis,401:NOT_FOUND:500,10,30
    

Circuit breaker status

By querying for the circuit breaker metrics, you can monitor the status of the circuit breaker:

actuator/metrics/resilience4j.circuitbreaker.state?tag=state:{circuit-breaker-state}&tag=name:{circuit-breaker-name}
  • where {circuit-breaker-state} is one of closed, disabled, half_open, forced_open, open, metrics_only
  • where {circuit-breaker-name} is the name of your circuit breaker, e.g. myCircuitBreaker

The metrics endpoint will return a value of 1 in the $.measurements[].value JSON path if the circuit breaker is in this state.

For more more information and other metrics, see Resilience4j CircuitBreaker Metrics.


ClientCertificateHeader

The ClientCertificateHeader filter validates the client SSL certificate used to make a request to an app through the Gateway. You can also use this filter to validate the client certificate's fingerprint.

When adding a route to a Gateway service instance, you can add the ClientCertificateHeader filter by including it in the list of filters for the applicable route.

$ cf bind-service cook my-gateway -c '{ "routes": [ { "path": "/cook/**", "filters": ["ClientCertificateHeader=*.example.com"] } ] }'

To validate the client SSL certificate's fingerprint, add the name of the hash used for the fingerprint, and the fingerprint value, after the CN, using the following format:

[CN],[HASH]:[FINGERPRINT]

where:

  • [CN] is the Common Name
  • [HASH] is the hash used for the fingerprint, either sha-1 or sha-256
  • [FINGERPRINT] is the fingerprint value

The following example uses the ClientCertificateHeader filter to ensure that a client certificate uses a CN of *.example.com and a SHA-1 fingerprint of aa:bb:00:99:

$ cf bind-service cook my-gateway -c '{ "routes": [ { "path": "/cook/**", "filters": ["ClientCertificateHeader=*.example.com,sha-1:aa:bb:00:99"] } ] }'

The fingerprint value is not case-sensitive, and the colon character : is not required to separate hexadecimal digits in a fingerprint. The following example works too:

$ cf bind-service cook my-gateway -c '{ "routes": [ { "path": "/cook/**", "filters": ["ClientCertificateHeader=*.example.com,sha-1:AABB0099"] } ] }'

FallbackHeaders

When a circuit breaker 'opens' and redirects a request to a fallback destination because the intended destination has returned an exception, it is sometimes useful for the fallback destination to receive information about the failure that just occurred. To facilitate this, the FallbackHeaders filter can be used to write the details of the exception into the headers of any requests forwarded to a fallback route.

The default header names added by the filter, and their values, are:

  • Execution-Exception-Type

    The type (Java class) of the exception that tripped the circuit breaker

  • Execution-Exception-Message

    The message attached to the exception that tripped the circuit breaker

  • Root-Cause-Exception-Type

    The type (Java class) of the root cause exception, if available

  • Root-Cause-Exception-Message

    The message attached to the root cause exception, if available

The example FallbackHeaders filter configuration below adds the exception information from failures in the /cook/** route to the fallback requests made to the /inCaseOfFailureUseThis route:

$ cf bind-service cook my-gateway -c '{ "routes": [ { "path": "/cook/**", "filters":["CircuitBreaker=myCircuitBreaker,forward:/fallback"] }, { "path": "/fallback", "filters": ["FallbackHeaders"]} ] }'

You can optionally configure the names of the headers used by the filter, by appending a comma-separated list to the configuration. The alternative header names must be given in the same order as the default names listed above. So, the following configuration would update the Execution-Exception-Type header name to My-Execution-Exception-Type:

      "FallbackHeaders=My-Execution-Exception-Type, My-Execution-Exception-Message, My-Root-Cause-Exception-Type, My-Root-Cause-Exception-Message"

LocalResponseCache

This filter allows to define a cache that can be applied at route-level. Some considerations must be taken into account when activating this feature:

  • It only handles bodyless GET requests.
  • It only caches the response as long has one of the following status codes: HTTP 200 (OK), HTTP 206 (Partial Content) and HTTP 301 (Moved Permanently).
  • Response data will not be cached if Cache-Control header doesn't allow it (no-store in the request, no-store or private in the response).
  • If response is already cached and a new request is performed with no-cache value in Cache-Control header, it will return a bodiless response with 304 (Not Modified).

It accepts two configuration parameters: first the timeToLive parameter that sets the time to expire a cache entry (expressed in s for seconds, m for minutes, and h for hours), and then, the size parameter that sets the maximum size of the cache to evict entries for this route (in KB, MB and GB). If none of them are specified, the default configuration will be taken from Configure HTTP response cache guide.

To add a local response cache of 1MB with a time to live of 50s to the /cached/** route, set:

$ cf bind-service cook my-gateway -c '{ "routes": [ { "path": "/cached/**", "filters": ["LocalResponseCache=50s,1MB"] } ] }'

This filter also implements the automatic calculation of the max-age value in the HTTP Cache-Control header. Only if "max-age" is present on the original response the value will be rewritten with the number of seconds set in the timeToLive configuration parameter; and in consecutive calls this value will be recalculated with the number of seconds left until the response expires.


RateLimit

The RateLimit filter limits the number of requests allowed per route during a time window. It can apply rate limits to all requests to a route, or optionally per user or per source IP address.

By default, Session Management and Rate Limiting use Hazelcast as the default cache implementation. If the operator makes Redis available, developers can opt-in to Redis by setting cache to redis. When activated, a Redis service instance automatically be created and bound to the gateway.

Caution Activating Redis for the RateLimit filter implicitly activates the use of Redis for session storage. When updating a running instance, any request count or user session data previously held in Hazelcast will not be migrated.

Rate limiting is activated for a route by adding RateLimit to its list of filters. The RateLimit filter configuration accepts four parameters in the following order:

  1. The maximum number of requests to be accepted during the window.
  2. The duration of the window. By default this is specified in milliseconds, but you can use the s, m or h suffixes to specify it in seconds, minutes or hours respectively.
  3. (Optional) User partition key. This allows different rate limits to be specified for different users, based on a user identifier to be found in the request. Set whether the key is to be found in a JWT claim or HTTP header with the {claim:CLAIM_NAME} or {header:HEADER_NAME} syntax.
  4. (Optional) Source IP address, if the rate limit should be applied only to requests from a certain source. This cannot be combined with per user rate limits.

Basic rate limiting

The rate limit configuration shown below will perform basic limiting of the number requests allowed during a time window. In this example, a maximum of 1 request to the /cook/** route will be allowed every 10 seconds:

$ cf bind-service cook my-gateway -c '{ "routes": [ { "path": "/cook/**", "filters": ["RateLimit=1,10s"] } ] }'

When requests are made at a rate allowed by the configured limit, the responses will succeed and report the remaining number of requests that can be made within the limit in the X-Remaining HTTP header. When the limit is exceeded, responses will fail with the 429 Too Many Requests status. The remaining time until requests will be allowed again is returned in the X-Retry-In HTTP header (specified in milliseconds).

Per-user rate limiting, partitioned by HTTP header

Below is an example configuration illustrating per-user rate limiting, where the user is identified from the contents of an HTTP header. In this example, an API key identifies the user, and is retrieved from the the X-API-Key header:

$ cf bind-service cook my-gateway -c '{ "routes": [ { "path": "/cook/**", "filters": ["RateLimit=1,10s,{header:X-API-Key}"] } ] }'

An individual rate limit of one request per ten seconds will be applied for each group of users sharing the same API key.

When requests for a given X-API-Key header exceed the defined limit in a time window, then access will be rejected with a simple 429 Too Many Requests response, with no additional headers.

Per-user rate limiting, partitioned by JWT claim

Similarly, the example configuration below illustrates per-user rate limiting again, this time with the user being identified by the value of the client-id claim of the JWT authorization token associated with the request:

$ cf bind-service cook my-gateway -c '{ "routes": [ { "path": "/cook/**", "filters": ["RateLimit=1,10s,{claim:client-id}"] } ] }'

When requests for a given client-id value exceed the defined limit in a time window, then access will be rejected with a simple 429 Too Many Requests response, with no additional headers.

Limiting by IP address

To limit by IP address, the RateLimit filter configuration accepts a semi-colon separated list of source IP addresses from which to accept requests.

The filter checks the X-Forwarded-For header, if present, for the source IP address of the request. Since multiple IP addresses may have been added to the X-Forwarded-For header by multiple trusted or untrusted proxies, you can optionally set the maximum trusted index of the IP to read from the header, by prepending an integer value to the IP address list. The default value of 1 will read the last IP from the header, while a value of 2 will read up to the second from last IP, and so on. The index value must be greater than zero.

Here is an example configuration to rate limit by IP address:

$ cf bind-service cook my-gateway -c '{ "routes": [ { "path": "/cook/**", "filters": ["RateLimit=1,10s,{IPs:2;127.0.0.1;192.168.0.1}"] } ] }'

In this example, a maximum of 1 request is allowed in a 10s window, as long as it originates from any of the configured IPs: 127.0.0.1 and 192.168.0.1.

The maximum trusted index to read from the X-Forwarded-For header is set to 2. If, for example, the X-Forwarded-For header had a value of 4.4.4.4, 8.8.8.8, 127.0.0.1, the gateway would return 403 Forbidden because the second-last IP, 8.8.8.8, is not in the allowed list. However, if the header was instead set to 4.4.4.4, 127.0.0.1, 8.8.8.8, then the gateway would return successfully, because the second-last IP would then be 127.0.0.1, and this is in the allowed list.

check-circle-line exclamation-circle-line close-line
Scroll to top icon