[In-depth analysis of spring cloud gateway] 03 Gateway built-in filter factory (GatewayFilter Factories)

1. Quick start

Route filters allow modification of incoming HTTP requests and outgoing HTTP responses. Spring Cloud Gateway includes a number of built-in GatewayFilter Factories.
Filters are generally used together with predicates. When the xxx condition is met, the logic of a certain filter is executed.

Routes can be configured through configuration files and codes.
The following is how to write java code:

@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();
}

The configuration is written briefly, see the example below.

2. Basic principles

The function of GatewayFilterFactory is to generate GatewayFilter.
The function of GatewayFilter is to process requests or return messages.
The following is a piece of source code. The function of the GatewayFilter is to add a request header, and this request header is defined in the configuration file.

public class AddRequestHeaderGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
    
    

    @Override
    public GatewayFilter apply(NameValueConfig config) {
    
    
        return new GatewayFilter() {
    
    
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    
    
                String value = ServerWebExchangeUtils.expand(exchange, config.getValue());
                ServerHttpRequest request = exchange.getRequest().mutate()
                        .headers(httpHeaders -> httpHeaders.add(config.getName(), value)).build();

                return chain.filter(exchange.mutate().request(request).build());
            }

            @Override
            public String toString() {
    
    
                return filterToStringCreator(AddRequestHeaderGatewayFilterFactory.this)
                        .append(config.getName(), config.getValue()).toString();
            }
        };
    }

}

The essence of GateWayFilterFactory is to parse the configuration and add Filter to the specified route in order to process the request message.

3. Filter Example

3.1 The AddRequestHeader GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
      - id: add_request_header_route
        uri: https://example.org
        predicates:
        - Path=/red/{
    
    segment}
        filters:
        - AddRequestHeader=X-Request-Red, Blue-{
    
    segment}

Add header information: X-Request-Red, value is Blue-{segment}, segment is the information in the path

3.2 The AddRequestParameter GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
      - id: add_request_parameter_route
        uri: https://example.org
        predicates:
        - Host: {
    
    segment}.myhost.org
        filters:
        - AddRequestParameter=foo, bar-{
    
    segment}

Add parameters name=foo,value=bar-{segment}

3.3 The AddResponseHeader GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
      - id: add_response_header_route
        uri: https://example.org
        predicates:
        - Host: {
    
    segment}.myhost.org
        filters:
        - AddResponseHeader=foo, bar-{
    
    segment}

Add return header information name=foo,value=bar-{segment}

3.4 The DedupeResponseHeader GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
      - id: dedupe_response_header_route
        uri: https://example.org
        filters:
        - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin

Duplicate response headers will be removed when both gateway CROS and downstream response headers have Access-Control-Allow-Credentials and Access-Control-Allow-Origin

3.5 Spring Cloud CircuitBreaker GatewayFilter Factory

Use Spring Cloud CircuitBreaker's API to wrap gateway routes into circuit breakers. Spring Cloud CircuitBreaker supports multiple libraries for use with Spring Cloud Gateway. For example, Resilience4J.
To enable the Spring Cloud CircuitBreaker filter, you need to introduce spring-cloud-starter-circuitbreaker-reactor-resilience4j. The following is a configuration example

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

RewritePath means rewriting the /consumingServiceEndpoint path to /backingServiceEndpoint
fallbackUri before requesting, that is, requests after circuit breaker need to jump to this path. This path can be provided by the gateway itself. For example: the gateway can provide a Controller with the path /inCaseOfFailureUseThis
is how the java code is written:

@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();
}
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

This example is to jump to the /fallback path after the fuse is broken. The /fallback path happens to be provided by another service (http://localhost:9994)

3.6 The FallbackHeaders GatewayFilter Factory

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

The FallbackHeaders GatewayFilter Factory
In this example, after an exception occurs while running circuit breaker, the request will be forwarded to /fallback at http://localhost:9994. Exception type, message, etc. are added to the request header through the FallbackHeaders filter.
The names of headers can be overridden in the configuration by setting the parameter values ​​listed below.

executionExceptionTypeHeaderName ("Execution-Exception-Type")
executionExceptionMessageHeaderName ("Execution-Exception-Message")
rootCauseExceptionTypeHeaderName ("Root-Cause-Exception-Type")
rootCauseExceptionMessageHeaderName ("Root-Cause-Exception-Message")

3.7 The MapRequestHeader GatewayFilter Factory

Receives two parameters, namely fromHeader and toHeader. It creates a new header (toHeader) and extracts the value from fromHeader. If the input header does not exist, the filter will not be executed. If the new header already exists, then it will be appended with the new value. As follows:

spring:
  cloud:
    gateway:
      routes:
      - id: map_request_header_route
        uri: https://example.org
        filters:
        - MapRequestHeader=Blue, X-Request-Red

This example will add an X-Request-Red: header to the downstream request, with the value being the incoming HTTP request Blue value.

3.8 The PrefixPath GatewayFilter Factory

Receive a parameter prefix

spring:
  cloud:
    gateway:
      routes:
      - id: prefixpath_route
        uri: https://example.org
        filters:
        - PrefixPath=/mypath

This example will prefix all matching request paths with /mypath, so when /hello is requested, it will be sent to /mypath/hello.

3.9 The PreserveHostHeader GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
      - id: preserve_host_route
        uri: https://example.org
        filters:
        - PreserveHostHeader

This filtering factory receives no parameters. After setting this Filter, the GatewayFilter will not use the host header determined by the HTTP client, but will send the original host header.
For example, the host header of the gateway is localhost:8080, and the host header of the downstream service is 192.168.1.11:8080. What is returned here is the host of the gateway, that is, localhost:8080.

3.10 The RequestRateLimiter GatewayFilter Factory

This filter uses RateLimiter to determine whether to allow the request to continue executing. If execution is not allowed to continue, HTTP 429 - Too
Many Requests is returned (by default).
This filter can be configured with an optional keyResolver parameter and rate limiter parameter.
keyResolver is an implementation class of KeyResolver. In the configuration, use SpEL to reference the bean by name. #{@myKeyResolver} is
a SpEL expression that references the bean named 'myKeyResolver'.

public interface KeyResolver {
    
    
    Mono<String> resolve(ServerWebExchange exchange);
}

The KeyResolver interface allows the use of pluggable strategies to derive keys that limit requests. In future milestone releases, there will be some KeyResolver implementations.
The default implementation of KeyResolver is PrincipalNameKeyResolver, which retrieves the Principal from ServerWebExchange and calls Principal.getName().
By default, if the KeyResolver does not obtain the key, the request will be rejected. You can adjust it with the following settings:

spring.cloud.gateway.filter.request-rate-limiter.deny-empty-key (true or false)
spring.cloud.gateway.filter.request-rate-limiter.empty-key-status-code

RequestRateLimiter cannot be configured using "shortcut". The following configuration is invalid:

# INVALID SHORTCUT CONFIGURATION
spring.cloud.gateway.routes[0].filters[0]=RequestRateLimiter=2, 2, #{@userkeyresolver}

3.10.1 Redis RateLimiter (demo)

Redis implementation is based on Stripe. It needs to introduce the spring-boot-starter-data-redis-reactive dependency.
The algorithm used is Token Bucket Algorithm.
The redis-rate-limiter.replenishRate configuration is how many requests you allow users to perform per second without discarding any requests. This is the filling rate of the token bucket.
The redis-rate-limiter.burstCapacity configuration is the maximum number of requests that users are allowed to perform in one second. This is the number of tokens that the token bucket can hold. Setting this value to 0 will block all requests.
redis-rate-limiter.requestedTokens configures the number of tokens required for a request. The number of tokens extracted from the token bucket for each request. The default is 1.
Achieve a stable rate by setting the same value in replenishRate and burstCapacity. Temporary bursts of traffic can be allowed by setting burstCapacity higher than replenishRate. In this case, the rate limiter needs to allow some time between bursts (according to replenishRate), because two consecutive bursts will cause requests to be lost (HTTP 429 - Too Many Requests). The following list configures a redis-rate-limiter:
For example: replenishRate=1, requestedTokens=60 and burstCapacity=60 will be limited to 1 request/min.

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

Configure a KeyResolver

@Bean
KeyResolver userKeyResolver() {
    
    
    return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
}

This defines a limit of 10 requests per user. 20 bursts are allowed, but only 10 requests are available the next second. KeyResolver is a simple
tool for obtaining user request parameters (note: not recommended for production).
The rate limiter can also be defined as an implementation bean of the RateLimiter interface. In the configuration, reference the bean by name using SpEL. #
{@myRateLimiter} is a SpEL expression that references the bean named myRateLimiter.

spring:
  cloud:
    gateway:
      routes:
      - id: requestratelimiter_route
        uri: https://example.org
        filters:
        - name: RequestRateLimiter
          args:
            rate-limiter: "#{@myRateLimiter}"
            key-resolver: "#{@userKeyResolver}"

3.11 The RedirectTo GatewayFilter Factory

Receives two parameters: status and url.
status is a 300 redirect HTTP code, such as 301. The url should be a valid URL and the value is the value of the Location header.
For relative paths, uri: no://op should be used as the route definition

spring:
  cloud:
    gateway:
      routes:
      - id: prefixpath_route
        uri: https://example.org
        filters:
        - RedirectTo=302, https://acme.org

This example will send a 302 redirect status code to Location: https://acme.org

3.12 The RemoveRequestHeader GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
      - id: removerequestheader_route
        uri: https://example.org
        filters:
        - RemoveRequestHeader=X-Request-Foo

Delete request header:X-Request-Foo

3.13 RemoveResponseHeader GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
      - id: removeresponseheader_route
        uri: https://example.org
        filters:
        - RemoveResponseHeader=X-Response-Foo

Delete return header:X-Response-Foo

3.14 The RemoveRequestParameter GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
      - id: removerequestparameter_route
        uri: https://example.org
        filters:
        - RemoveRequestParameter=red

Delete request parameters

3.15 The RewritePath GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
      - id: rewritepath_route
        uri: https://example.org
        predicates:
        - Path=/red/**
        filters:
        - RewritePath=/red(?<segment>/?.*), $\{
    
    segment}

For /red/blue request paths, will be replaced with /blue before being sent downstream. Because of the YAML specification, $ must be replaced with $\

3.16 RewriteLocationResponseHeader GatewayFilter Factory

This filter modifies the value of the Location response header and is often used to remove some sensitive information. The received parameters are:
stripVersionMode, locationHeaderName, hostValue, protocolsRegex

spring:
  cloud:
    gateway:
      routes:
      - id: rewritelocationresponseheader_route
        uri: http://example.org
        filters:
        - RewriteLocationResponseHeader=AS_IN_REQUEST, Location, ,

The example shows that a POST request api.example.com/some/object/name, the value of the Location response header is object-
service.prod.example.net/v2/some/object/id will be rewritten to api.example .com/some/object/id .
The stripVersionMode parameter has the following values: NEVER_STRIP, AS_IN_REQUEST (default), and ALWAYS_STRIP.
NEVER_STRIP: The original request does not contain the version, and the version will not be removed.
AS_IN_REQUEST: The original request does not contain the version, and the version will be removed from the response header.
ALWAYS_STRIP: The version will always be removed.
hostValue parameter: If this value is provided, it will be used to replace host:port. The value of the Location header in the response. If it is empty,
the header value named Host in the request is used .
The protocolsRegex parameter is a valid regular string. If there is no match, the filter does not execute. The default value is http | https | ftp | ftps

3.17 The RewriteResponseHeader GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
      - id: rewriteresponseheader_route
        uri: https://example.org
        filters:
        - RewriteResponseHeader=X-Response-Red, , password=[^&]+, password=***

After the downstream response returns to the gateway, this example will set the value of the /42?user=ford&password=omg!what&flag=true header to /42?user=ford&password=***&flag=true
. You must use $\ instead of $

3.18 The SaveSession GatewayFilter Factory

SaveSession GatewayFilter Factory forces a WebSession::save operation before forwarding the call downstream.
This is particularly useful when using something like Spring Session, where you need to ensure that the session state is saved before making the forward call

spring:
  cloud:
    gateway:
      routes:
      - id: save_session
        uri: https://example.org
        predicates:
        - Path=/foo/**
        filters:
        - SaveSession

This is important if you wish to integrate Spring Security with Spring Session and ensure that security information is passed downstream

3.19 The SecureHeaders GatewayFilter Factory

SecureHeaders GatewayFilter Factory adds many headers in the response.
Added the following headers (default)

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)

Use the spring.cloud.gateway.filter.secure-headers configuration to change the default value

xss-protection-header
strict-transport-security
x-frame-options
x-content-type-options
referrer-policy
content-security-policy
x-down-options
x-permitted-cross-domain-policies

Use spring.cloud.gateway.filter.secure-headers.disable to disable the default value, separated by commas in all lowercase letters

spring.cloud.gateway.filter.secure-headers.disable=x-frame-options,strict-transport-security

3.20 The SetPath GatewayFilter Factory

SetPath GatewayFilter Factory takes a template path parameter. It provides a simple way
to manipulate request paths by allowing templated segments of the path. Use URI templates in Spring Framework to allow multiple matching segments

spring:
  cloud:
    gateway:
      routes:
      - id: setpath_route
        uri: https://example.org
        predicates:
        - Path=/red/{
    
    segment}
        filters:
        - SetPath=/{
    
    segment}

As shown above: requesting /red/blue will set the path to /blue when requesting downstream

3.21 The SetRequestHeader GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
      - id: setrequestheader_route
        uri: https://example.org
        filters:
        - SetRequestHeader=X-Request-Red, Blue

This GatewayFilter will replace all headers with the given name instead of adding them. Therefore, the request header will
be set from X-Request-Red:1234 to X-Request-Red:Blue.
SetRequestHeader allows the use of path or host URI variables

spring:
  cloud:
    gateway:
      routes:
      - id: setrequestheader_route
        uri: https://example.org
        predicates:
        - Host: {
    
    segment}.myhost.org
        filters:
        - SetRequestHeader=foo, bar-{
    
    segment}

3.22 The SetResponseHeader GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
      - id: setresponseheader_route
        uri: https://example.org
        filters:
        - SetResponseHeader=X-Response-Red, Blue

This GatewayFilter will replace all headers with the given name instead of adding them. The downstream response header X-Response-Red:1234
will be replaced by X-Response-Red:Blue.
SetResponseHeader also uses the URI variable of path or host

spring:
  cloud:
    gateway:
      routes:
      - id: setresponseheader_route
        uri: https://example.org
        predicates:
        - Host: {
    
    segment}.myhost.org
        filters:
        - SetResponseHeader=foo, bar-{
    
    segment}

3.23 The SetStatus GatewayFilter Factory

Receives a parameter status, which must be an available Spring HttpStatus value, which can be an integer or an enumerated string.

spring:
  cloud:
    gateway:
      routes:
      - id: setstatusstring_route
        uri: https://example.org
        filters:
        - SetStatus=BAD_REQUEST
      - id: setstatusint_route
        uri: https://example.org
        filters:
        - SetStatus=401

This example sets the HTTP status response header to 401.
Use SetStatus to return the original HTTP status code in the proxy request in the response. Configure as follows to add the header to the response

spring:
  cloud:
    gateway:
      set-status:
        original-status-header-name: original-http-status

3.24 The StripPrefix GatewayFilter Factory

Receives a parts parameter. The parts parameter indicates the number of sections in the path to be removed from the request before sending it downstream.

spring:
  cloud:
    gateway:
      routes:
      - id: nameRoot
        uri: https://nameservice
        predicates:
        - Path=/name/**
        filters:
        - StripPrefix=2

This example shows that when the gateway sends a /name/blue/red request, the actual downstream request address is nameservice/red

3.25 The Retry GatewayFilter Factory

Retry GatewayFilter Factory uses the retry component of reactor-addons to retry and supports the following parameters:

retries:应尝试的重试次数
statuses:应尝试的HTTP状态码
methods:应尝试的HTTP⽅法
series:应尝试的series状态码, org.springframework.http.HttpStatus.Series
exceptions:应尝试的异常列表
backoff:配置指数退避重试。根据 firstBackoff * (factor ^ n) 进⾏指数重试, maxBackoff 限制最⼤

Backoff retry, if basedOnPreviousValue is true, the backoff index calculation uses prevBackoff * factor.
The default value of the Retry filter is configured as follows:
retries: 3 times
series: 5XX series
methods: GET method
exceptions: IOException and TimeoutException
backoff: disabled

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

When a retry filter is used with any HTTP request with a body, the body will be cached.
The body is cached in ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR defined in the request . The object type is: org.springframework.core.io.buffer.DataBuffer

3.26 The RequestSize GatewayFilter Factory

When the request size is larger than the allowed limit, the RequestSize GatewayFilter Factory can limit the request from reaching the downstream service. The filter takes
RequestSize as parameter, which is the allowed size limit that defines the request (in bytes)

spring:
  cloud:
    gateway:
      routes:
      - id: request_size_route
        uri: http://localhost:8080/upload
        predicates:
        - Path=/upload
        filters:
        - name: RequestSize
          args:
            maxSize: 5000000

When a request is rejected due to size, RequestSize GatewayFilter Factory sets the response status to 413 Payload Too Large
with additional header errorMessage errorMessage
Request :size is larger than permissible limit. Request size is 6.0 MB where permissible limit is 5.0 MB

3.27 The SetRequestHost GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
      - id: set_request_host_header_route
        uri: http://localhost:8080/headers
        predicates:
        - Path=/headers
        filters:
        - name: SetRequestHost
          args:
            host: example.org

This example indicates using example.org instead of the value of the host header.

3.28 Modify a Request Body GatewayFilter Factory

This filter can be used to modify the request body before it is sent downstream by the gateway

@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) -> return 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;
    }
}

3.29 Modify a Response Body GatewayFilter Factory

This filter can be used to modify the response body before sending it back to the client

@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();
}

4. Set Default Filters

You can use spring.cloud.gateway.default-filters as filters for all routes. This configuration receives a filter list, as follows

spring:
  cloud:
    gateway:
      default-filters:
      - AddResponseHeader=X-Response-Default-Red, Default-Blue
      - PrefixPath=/httpbin

5. Questions

  • Question 1: If there are only filters under routes and no predicates, what will be the effect? Does this filter intercept all requests or none?

  • Question 2: predicates and filters are plural, which means multiple predicates and multiple filters can be configured. How to configure them?
    The following example shows a configuration of two filters, using circuit breakers and rewriting path filters.

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

Guess you like

Origin blog.csdn.net/suyuaidan/article/details/132577342