115. GatewayFilter Factories

路由filter允许以某种方式修改传入的 HTTP 请求或传出的 HTTP 响应。路由filter适用于特定路由。 Spring Cloud Gateway 包括许多内置的 GatewayFilter 工厂。

注意有关如何使用以下任何filter的更多详细示例,请查看unit tests

115.1 AddRequestHeader GatewayFilter 工厂

AddRequestHeader GatewayFilter 工厂采用名称和值参数。

application.yml.

spring:
  cloud:
    gateway:
      routes:
      - id: add_request_header_route
        uri: http://example.org
        filters:
        - AddRequestHeader=X-Request-Foo, Bar

这会将X-Request-Foo:BarHeaders 添加到所有匹配请求的下游请求 Headers 中。

115.2 AddRequestParameter GatewayFilter 工厂

AddRequestParameter GatewayFilter 工厂采用名称和值参数。

application.yml.

spring:
  cloud:
    gateway:
      routes:
      - id: add_request_parameter_route
        uri: http://example.org
        filters:
        - AddRequestParameter=foo, bar

对于所有匹配的请求,这会将foo=bar添加到下游请求的查询字符串中。

115.3 AddResponseHeader GatewayFilter 工厂

AddResponseHeader GatewayFilter 工厂采用名称和值参数。

application.yml.

spring:
  cloud:
    gateway:
      routes:
      - id: add_request_header_route
        uri: http://example.org
        filters:
        - AddResponseHeader=X-Response-Foo, Bar

这会将X-Response-Foo:BarHeaders 添加到所有匹配请求的下游响应的 Headers 中。

115.4 Hystrix GatewayFilter 工厂

Hystrix是 Netflix 的实现断路器模式的库。 Hystrix GatewayFilter 允许您将断路器引入网关路由,保护您的服务免受级联故障的影响,并允许您在下游故障的情况下提供后备响应。

要在您的项目中启用 Hystrix GatewayFilters,请从Spring Cloud Netflix添加对spring-cloud-starter-netflix-hystrix的依赖。

Hystrix GatewayFilter 工厂需要一个name参数,即HystrixCommand的名称。

application.yml.

spring:
  cloud:
    gateway:
      routes:
      - id: hystrix_route
        uri: http://example.org
        filters:
        - Hystrix=myCommandName

这会将其余filter包装在命令名称为myCommandNameHystrixCommand中。

Hystrix filter还可以接受可选的fallbackUri参数。当前,仅支持forward:个计划的 URI。如果调用后备,则请求将被转发到与 URI 相匹配的控制器。

application.yml.

spring:
  cloud:
    gateway:
      routes:
      - id: hystrix_route
        uri: lb://backing-service:8088
        predicates:
        - Path=/consumingserviceendpoint
        filters:
        - name: Hystrix
          args:
            name: fallbackcmd
            fallbackUri: forward:/incaseoffailureusethis
        - RewritePath=/consumingserviceendpoint, /backingserviceendpoint

调用 Hystrix 后备时,它将转发到/incaseoffailureusethis URI。请注意,此示例还通过目标 URI 上的lb前缀演示了(可选)Spring Cloud Netflix Ribbon 负载平衡。

主要方案是将fallbackUri用于网关应用程序中的内部控制器或处理程序。但是,也可以将请求重新路由到外部应用程序中的控制器或处理程序,如下所示:

application.yml.

spring:
  cloud:
    gateway:
      routes:
      - id: ingredients
        uri: lb://ingredients
        predicates:
        - Path=//ingredients/**
        filters:
        - name: Hystrix
          args:
            name: fetchIngredients
            fallbackUri: forward:/fallback
      - id: ingredients-fallback
        uri: http://localhost:9994
        predicates:
        - Path=/fallback

在此示例中,网关应用程序中没有fallback终结点或处理程序,但是另一个应用程序中没有fallback终结点或处理程序,并在http://localhost:9994下注册。

如果将请求转发给后备,则 Hystrix 网关filter还会提供引起该请求的Throwable。它已作为ServerWebExchangeUtils.HYSTRIX_EXECUTION_EXCEPTION_ATTR属性添加到ServerWebExchange,可在网关应用程序中处理后备时使用。

对于外部控制器/处理程序方案,可以添加带有异常详细信息的 Headers。您可以在FallbackHeaders GatewayFilter 工厂部分中找到更多信息。

Hystrix 设置(例如超时)可以使用全局默认值配置,也可以使用Hystrix wiki上说明的应用程序属性在逐条路由的基础上进行配置。

要为上述示例路由设置 5 秒超时,将使用以下配置:

application.yml.

hystrix.command.fallbackcmd.execution.isolation.thread.timeoutInMilliseconds: 5000

115.5 FallbackHeaders GatewayFilter 工厂

FallbackHeaders工厂允许您在转发到外部应用程序中fallbackUri的请求的 Headers 中添加 Hystrix 执行异常详细信息,如以下情况:

application.yml.

spring:
  cloud:
    gateway:
      routes:
      - id: ingredients
        uri: lb://ingredients
        predicates:
        - Path=//ingredients/**
        filters:
        - name: Hystrix
          args:
            name: fetchIngredients
            fallbackUri: forward:/fallback
      - id: ingredients-fallback
        uri: http://localhost:9994
        predicates:
        - Path=/fallback
        filters:
        - name: FallbackHeaders
          args:
            executionExceptionTypeHeaderName: Test-Header

在此示例中,在运行HystrixCommand时发生执行异常后,该请求将转发到localhost:9994上运行的应用程序中的fallback端点或处理程序。带有异常类型,消息和-if available-根本原因异常类型和消息的 Headers 将由FallbackHeadersfilter添加到该请求。

通过设置下面列出的参数的值及其默认值,可以在配置中覆盖 Headers 的名称:

  • executionExceptionTypeHeaderName ( "Execution-Exception-Type" )

  • executionExceptionMessageHeaderName ( "Execution-Exception-Message" )

  • rootCauseExceptionTypeHeaderName ( "Root-Cause-Exception-Type" )

  • rootCauseExceptionMessageHeaderName ( "Root-Cause-Exception-Message" )

您可以在Hystrix GatewayFilter 工厂部分中找到有关 Hystrix 如何与 Gateway 一起使用的更多信息。

115.6 PrefixPath GatewayFilter 工厂

PrefixPath GatewayFilter 工厂采用单个prefix参数。

application.yml.

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

这会将/mypath作为所有匹配请求的路径的前缀。因此,对/hello的请求将发送到/mypath/hello

115.7 PreserveHostHeader GatewayFilter 工厂

PreserveHostHeader GatewayFilter 工厂没有参数。此filter设置请求属性,路由filter将检查该请求属性以确定是否应发送原始主机头,而不是由 HTTPClient 端确定的主机头。

application.yml.

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

115.8 RequestRateLimiter GatewayFilter 工厂

RequestRateLimiter GatewayFilter 工厂使用RateLimiter实现来确定是否允许 continue 当前请求。如果不是,则返回状态HTTP 429 - Too Many Requests(默认)。

该filter采用可选的keyResolver参数和特定于速率限制器的参数(请参见下文)。

keyResolver是实现KeyResolver接口的 bean。在配置中,使用 SpEL 按名称引用 bean。 #{@myKeyResolver}是一个 SpEL 表达式,它引用名称为myKeyResolver的 bean。

KeyResolver.java.

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

KeyResolver接口允许可插拔策略派生用于限制请求的密钥。在 Future 的里程碑中,将有KeyResolver个实现。

KeyResolver的默认实现是PrincipalNameKeyResolver,它从ServerWebExchange检索Principal并调用Principal.getName()

默认情况下,如果KeyResolver找不到密钥,则请求将被拒绝。可以使用spring.cloud.gateway.filter.request-rate-limiter.deny-empty-key(正确或错误)和spring.cloud.gateway.filter.request-rate-limiter.empty-key-status-code属性来调整此行为。

Note

无法通过“快捷方式”符号配置 RequestRateLimiter。以下示例是无效

application.properties.

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

115.8.1 Redis RateLimiter

redis 实现基于Stripe完成的工作。它需要使用spring-boot-starter-data-redis-reactive Spring Boot 启动程序。

使用的算法是令牌桶算法

redis-rate-limiter.replenishRate是您希望用户每秒允许多少个请求,而没有任何丢弃的请求。这是令牌桶被填充的速率。

redis-rate-limiter.burstCapacity是允许用户在一秒钟内执行的最大请求数。这是令牌桶可以容纳的令牌数。将此值设置为零将阻止所有请求。

通过在replenishRateburstCapacity中设置相同的值可以达到稳定的速率。可以通过将burstCapacity设置为高于replenishRate来允许临时突发。在这种情况下,由于两次连续的突发将导致请求丢弃(HTTP 429 - Too Many Requests),因此需要在两次突发之间有一定时间允许速率限制器(根据replenishRate)。

application.yml.

spring:
  cloud:
    gateway:
      routes:
      - id: requestratelimiter_route
        uri: http://example.org
        filters:
        - name: RequestRateLimiter
          args:
            redis-rate-limiter.replenishRate: 10
            redis-rate-limiter.burstCapacity: 20

Config.java.

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

这定义了每个用户 10 的请求速率限制。允许 20 个突发,但是下一秒只有 10 个请求可用。 KeyResolver是一个简单的参数,它获取user请求参数(注意:不建议在生产环境中使用)。

速率限制器也可以定义为实现RateLimiter接口的 bean。在配置中,使用 SpEL 按名称引用 bean。 #{@myRateLimiter}是一个 SpEL 表达式,它引用名称为myRateLimiter的 bean。

application.yml.

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

115.9 重定向到 GatewayFilter 工厂

RedirectTo GatewayFilter 工厂采用statusurl参数。状态应该是 300 系列重定向 http 代码,例如 301.URL 应该是有效的 URL。这将是LocationHeaders 的值。

application.yml.

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

这将发送带有Location:http://acme.orgHeaders 的状态 302 以执行重定向。

115.10 RemoveNonProxyHeaders GatewayFilter 工厂

RemoveNonProxyHeaders GatewayFilter 工厂从转发的请求中删除 Headers。默认的 Headers 列表来自IETF

默认删除的标题为:

  • Connection

  • Keep-Alive

  • Proxy-Authenticate

  • Proxy-Authorization

  • TE

  • Trailer

  • Transfer-Encoding

  • Upgrade

要更改此设置,请将spring.cloud.gateway.filter.remove-non-proxy-headers.headers属性设置为要删除的标题名称列表。

115.11 RemoveRequestHeader GatewayFilter 工厂

RemoveRequestHeader GatewayFilter 工厂采用name参数。它是要删除的标题的名称。

application.yml.

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

这将删除X-Request-FooHeaders,然后将其发送到下游。

115.12 RemoveResponseHeader GatewayFilter 工厂

RemoveResponseHeader GatewayFilter 工厂采用name参数。它是要删除的标题的名称。

application.yml.

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

这将从响应中删除X-Response-FooHeaders,然后将其返回给网关 Client 端。

115.13 RewritePath GatewayFilter 工厂

RewritePath GatewayFilter 工厂采用路径regexp参数和replacement参数。这使用 Java 正则表达式提供了一种灵活的方式来重写请求路径。

application.yml.

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

对于/foo/bar的请求路径,这将在发出下游请求之前将路径设置为/bar。请注意,由于 YAML 规范,$\$取代。

115.14 RewriteResponseHeader GatewayFilter 工厂

RewriteResponseHeader GatewayFilter 工厂采用nameregexpreplacement参数。它使用 Java 正则表达式以灵活的方式重写响应 Headers 值。

application.yml.

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

对于 Headers 值/42?user=ford&password=omg!what&flag=true,在发出下游请求后它将被设置为/42?user=ford&password=***&flag=true。由于 YAML 规范,请使用$\来表示$

115.15 SaveSession GatewayFilter 工厂

在向下游转发调用之前,SaveSession GatewayFilter 工厂强制执行WebSession::save操作。这在将Spring Session之类的数据用于惰性数据存储时特别有用,并且需要确保在进行转接调用之前已保存会话状态。

application.yml.

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

如果您将Spring Security与 Spring Session 集成在一起,并且想要确保安全性详细信息已转发到远程进程,那么这一点至关重要。

115.16 SecureHeaders GatewayFilter 工厂

SecureHeaders GatewayFilter 工厂在来自此博客文章的建议处向响应中添加了许多 Headers。

添加以下 Headers(以及默认值):

  • 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

要更改默认值,请在spring.cloud.gateway.filter.secure-headers名称空间中设置适当的属性:

更改属性:

  • xss-protection-header

  • strict-transport-security

  • frame-options

  • content-type-options

  • referrer-policy

  • content-security-policy

  • download-options

  • permitted-cross-domain-policies

115.17 SetPath GatewayFilter 工厂

SetPath GatewayFilter 工厂采用路径template参数。通过允许路径的模板段,它提供了一种操作请求路径的简单方法。这使用了 Spring Framework 中的 uri 模板。允许多个匹配段。

application.yml.

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

对于/foo/bar的请求路径,这将在发出下游请求之前将路径设置为/bar

115.18 SetResponseHeader GatewayFilter 工厂

SetResponseHeader GatewayFilter 工厂采用namevalue参数。

application.yml.

spring:
  cloud:
    gateway:
      routes:
      - id: setresponseheader_route
        uri: http://example.org
        filters:
        - SetResponseHeader=X-Response-Foo, Bar

该 GatewayFilter 用给定名称替换所有 Headers,而不是添加。因此,如果下游服务器以X-Response-Foo:1234响应,则将其替换为X-Response-Foo:Bar,这是网关 Client 端将收到的内容。

115.19 SetStatus GatewayFilter 工厂

SetStatus GatewayFilter 工厂采用单个status参数。它必须是有效的 Spring HttpStatus。它可以是整数值404或枚举NOT_FOUND的字符串表示形式。

application.yml.

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

无论哪种情况,响应的 HTTP 状态都将设置为 401.

115.20 StripPrefix GatewayFilter 工厂

StripPrefix GatewayFilter 工厂采用一个参数partsparts参数指示在向下游发送请求之前,要从请求中剥离的路径中的部分数量。

application.yml.

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

通过网关向/name/bar/foo发出请求时,向nameservice发出的请求看起来像http://nameservice/foo

115.21 重试 GatewayFilter 工厂

重试 GatewayFilter 工厂将retriesstatusesmethodsseries作为参数。

  • retries:应重试的次数

  • statuses:应重试的 HTTP 状态代码,使用org.springframework.http.HttpStatus表示

  • methods:应重试的 HTTP 方法,使用org.springframework.http.HttpMethod表示

  • series:要重试的一系列状态代码,使用org.springframework.http.HttpStatus.Series表示

application.yml.

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

Note

重试filter当前不支持使用主体重试(例如,使用主体进行 POST 或 PUT 请求)。

Note

当使用带有forward:前缀 URL 的重试filter时,应仔细编写目标端点,以便在发生错误的情况下不会执行任何可能导致响应发送到 Client 端并提交的操作。例如,如果目标端点是带 Comments 的控制器,则目标控制器方法不应返回带有错误状态代码的ResponseEntity。相反,它应该抛出Exception或发出错误 signal,例如通过Mono.error(ex)返回值,可以将重试filter配置为通过重试处理。

115.22 RequestSize GatewayFilter 工厂

当请求大小大于允许的限制时,RequestSize GatewayFilter Factory 可以限制请求到达下游服务。filter以RequestSize作为参数,这是请求的允许大小限制(以字节为单位)。

application.yml.

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

当请求因大小而被拒绝时,RequestSize GatewayFilter Factory 将响应状态设置为413 Payload Too Large,并附加一个 HeaderserrorMessage。以下是此类errorMessage的示例。

errorMessage : Request size is larger than permissible limit. Request size is 6.0 MB where permissible limit is 5.0 MB

Note

如果未在路由定义中作为filter参数提供,则默认请求大小将设置为 5 MB。

115.23 修改请求正文 GatewayFilter 工厂

此filter被视为测试版,API 将来可能会更改

此filter可用于在网关将其发送到下游之前修改请求主体。

Note

只能使用 Java DSL 配置此filter

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

115.24 修改响应正文 GatewayFilter 工厂

此filter被视为测试版,API 将来可能会更改

此filter可用于在将响应正文发送回 Client 端之前对其进行修改。

Note

只能使用 Java DSL 配置此filter

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