Spring Cloud Gateway

Spring Cloud Gateway

本项目提供了一个构建在 Spring 生态之上的 API Gateway,包括:Spring 5、Spring Boot 2 和 Project Reactor。Spring Cloud Gateway 旨在提供一种简单而有效的方式来路由到 API,并为它们提供横切关注点,例如:安全性、监控/指标和弹性。

如何包含Spring Cloud Gateway

要将 Spring Cloud Gateway 包含在您的项目中,请使用组 IDorg.springframework.cloud和工件 ID 的启动器spring-cloud-starter-gateway

如果包含启动器,但不希望启用网关,请设置spring.cloud.gateway.enabled=false.

Spring Cloud Gateway 需要 Spring Boot 和 Spring Webflux 提供的 Netty 运行时。它不适用于传统的 Servlet 容器或构建为 WAR 时。

词汇表

  • Route:网关的基本构建块。它由 ID、目标 URI、谓词集合和过滤器集合定义。如果聚合谓词为真,则匹配路由。
  • 谓词:这是一个Java 8 函数谓词。输入类型是Spring FrameworkServerWebExchange。这使您可以匹配来自 HTTP 请求的任何内容,例如标头或参数。
  • 过滤器GatewayFilter:这些是使用特定工厂构建的实例。在这里,您可以在发送下游请求之前或之后修改请求和响应。

它是如何工作的

下图提供了 Spring Cloud Gateway 如何工作的高级概述:

Spring Cloud Gateway

客户端向 Spring Cloud Gateway 发出请求。如果网关处理程序映射确定请求与路由匹配,则将其发送到网关 Web 处理程序。此处理程序通过特定于请求的过滤器链运行请求。过滤器用虚线划分的原因是过滤器可以在发送代理请求之前和之后运行逻辑。执行所有“预”过滤器逻辑。然后发出代理请求。发出代理请求后,将运行“发布”过滤器逻辑。

配置路由谓词工厂和网关过滤工厂

有两种配置谓词和过滤器的方法:快捷方式和完全扩展的参数。下面的大多数示例都使用快捷方式。

名称和参数名称将code在每个部分的第一句或第二句中列出。参数通常按快捷方式配置所需的顺序列出。

快捷方式配置

快捷方式配置由过滤器名称识别,后跟等号 ( =),后跟以逗号 ( ,) 分隔的参数值。

应用程序.yml

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - Cookie=mycookie,mycookievalue

前面的示例Cookie使用两个参数定义了路由谓词工厂,cookie 名称mycookie和要匹配的值mycookievalue

完全扩展的参数

完全扩展的参数看起来更像是带有名称/值对的标准 yaml 配置。通常,会有一把name钥匙和一把args钥匙。键是用于配置谓词或过滤器的args键值对映射。

应用程序.yml

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - name: Cookie
          args:
            name: mycookie
            regexp: mycookievalue

Cookie这是上面显示的谓词的快捷配置的完整配置。

路由谓词工厂

Spring Cloud Gateway 将路由匹配为 Spring WebFluxHandlerMapping基础架构的一部分。Spring Cloud Gateway 包含许多内置的路由谓词工厂。所有这些谓词都匹配 HTTP 请求的不同属性。您可以将多个路由谓词工厂与逻辑and语句结合起来。

After Route 谓词工厂

所述After路线谓词工厂有一个参数,一个datetime(其是Java ZonedDateTime)。此谓词匹配在指定日期时间之后发生的请求。以下示例配置了一个 after 路由谓词:

示例 1.application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - After=2017-01-20T17:42:47.789-07:00[America/Denver]

此路线匹配 2017 年 1 月 20 日 17:42 Mountain Time(丹佛)之后提出的任何请求。

Before 路由谓词工厂

所述Before路线谓词工厂有一个参数,一个datetime(其是Java ZonedDateTime)。此谓词匹配在指定的 之前发生的请求datetime。以下示例配置了一个 before 路由谓词:

示例 2.application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: before_route
        uri: https://example.org
        predicates:
        - Before=2017-01-20T17:42:47.789-07:00[America/Denver]

此路线与 2017 年 1 月 20 日 17:42 Mountain Time (Denver) 之前提出的任何请求相匹配。

Between 谓词工厂

Between路线谓词工厂有两个参数,datetime1并且datetime2 这是JavaZonedDateTime对象。此谓词匹配发生在 afterdatetime1和 before 的请求datetime2。该datetime2参数必须是后datetime1。以下示例配置了一个 between 路由谓词:

示例 3.application.yml

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]

此路线匹配 2017 年 1 月 20 日 17:42 山区时间(丹佛)和 2017 年 1 月 21 日 17:42 山区时间(丹佛)之前提出的任何请求。这对于维护窗口可能很有用。

Cookie 路由谓词工厂

Cookie路由谓词工厂有两个参数,cookie和namea regexp(这是一个 Java 正则表达式)。此谓词匹配具有给定名称且其值与正则表达式匹配的 cookie。以下示例配置 cookie 路由谓词工厂:

示例 4.application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: cookie_route
        uri: https://example.org
        predicates:
        - Cookie=chocolate, ch.p

此路由匹配具有名为chocolate其值与ch.p正则表达式匹配的 cookie 的请求。

标头路由谓词工厂

Header路由谓词工厂有两个参数,the和headera regexp(这是一个 Java 正则表达式)。此谓词与具有给定名称且值与正则表达式匹配的标头匹配。以下示例配置了一个标头路由谓词:

示例 5.application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: header_route
        uri: https://example.org
        predicates:
        - Header=X-Request-Id, \d+

如果请求具有一个名为X-Request-Id其值与\d+正则表达式匹配的标头(即,它具有一个或多个数字的值),则此路由匹配。

主机路由谓词工厂

Host路线谓词工厂需要一个参数:主机名的列表patterns。该模式是一种 Ant 风格的模式,.以分隔符为分隔符。此谓词匹配Host与模式匹配的标头。以下示例配置主机路由谓词:

示例 6.application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: host_route
        uri: https://example.org
        predicates:
        - Host=**.somehost.org,**.anotherhost.org

{sub}.myhost.org还支持URI 模板变量(例如)。

如果请求具有Host值为www.somehost.orgorbeta.somehost.org或的标头,则此路由匹配www.anotherhost.org

此谓词将 URI 模板变量(例如sub,在前面的示例中定义)提取为名称和值的映射,并将其放置在 中,ServerWebExchange.getAttributes()其中的键定义为ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE。然后这些值可供GatewayFilter工厂使用

方法路由谓词工厂

MethodRoute Predicate Factory 接受一个参数,该methods参数是一个或多个参数:要匹配的 HTTP 方法。以下示例配置方法路由谓词:

示例 7.application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: method_route
        uri: https://example.org
        predicates:
        - Method=GET,POST

GET如果请求方法是 a或 a ,则此路由匹配POST

路径路由谓词工厂

PathRoute Predicate Factory 有两个参数:一个 Spring 列表PathMatcher patterns和一个名为matchTrailingSlash(默认为)的可选标志true。以下示例配置路径路由谓词:

示例 8.application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: path_route
        uri: https://example.org
        predicates:
        - Path=/red/{segment},/blue/{segment}

如果请求路径是,则此路由匹配,例如:/red/1or/red/1//red/blueor /blue/green

如果matchTrailingSlash设置为false,则请求路径/red/1/将不匹配。

此谓词将 URI 模板变量(例如segment,在前面的示例中定义)提取为名称和值的映射,并将其放置在 中,ServerWebExchange.getAttributes()其中的键定义为ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE。然后这些值可供GatewayFilter工厂使用

可以使用一种实用方法(称为get)来更轻松地访问这些变量。以下示例显示了如何使用该get方法:

Map<String, String> uriVariables = ServerWebExchangeUtils.getPathPredicateVariables(exchange);

String segment = uriVariables.get("segment");

查询路由谓词工厂

Query路由谓词工厂有两个参数:一个必需的param和一个可选的regexp(它是一个 Java 正则表达式)。以下示例配置查询路由谓词:

示例 9.application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: query_route
        uri: https://example.org
        predicates:
        - Query=green

如果请求包含green查询参数,则前面的路由匹配。

应用程序.yml

spring:
  cloud:
    gateway:
      routes:
      - id: query_route
        uri: https://example.org
        predicates:
        - Query=red, gree.

如果请求包含red其值与正则gree.表达式匹配的查询参数,则前面的路由匹配,因此green并且greet会匹配。

RemoteAddr 路由谓词工厂

路由谓词工厂采用的RemoteAddr列表(最小大小为 1)sources,它们是 CIDR 表示法(IPv4 或 IPv6)字符串,例如192.168.0.1/16(其中192.168.0.1是 IP 地址和16子网掩码)。以下示例配置 RemoteAddr 路由谓词:

示例 10.application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: remoteaddr_route
        uri: https://example.org
        predicates:
        - RemoteAddr=192.168.1.1/24

例如,如果请求的远程地址是 ,则此路由匹配192.168.1.10

修改远程地址的解析方式

默认情况下,RemoteAddr 路由谓词工厂使用来自传入请求的远程地址。如果 Spring Cloud Gateway 位于代理层后面,这可能与实际客户端 IP 地址不匹配。

您可以通过设置自定义来自定义解析远程地址的方式RemoteAddressResolver。Spring Cloud Gateway 带有一个基于X-Forwarded-For 标头的非默认远程地址解析器,XForwardedRemoteAddressResolver.

XForwardedRemoteAddressResolver 有两个静态构造方法,它们采用不同的安全方法:

  • XForwardedRemoteAddressResolver::trustAll返回RemoteAddressResolver始终采用在X-Forwarded-For标头中找到的第一个 IP 地址的 a。这种方法容易受到欺骗,因为恶意客户端可以为 设置初始值,X-Forwarded-For解析器会接受该值。
  • XForwardedRemoteAddressResolver::maxTrustedIndex采用与 Spring Cloud Gateway 前运行的受信任基础架构数量相关的索引。例如,如果 Spring Cloud Gateway 只能通过 HAProxy 访问,则应使用值 1。如果在访问 Spring Cloud Gateway 之前需要两跳可信基础架构,则应使用值 2。

考虑以下标头值:

X-Forwarded-For: 0.0.0.1, 0.0.0.2, 0.0.0.3

以下maxTrustedIndex值产生以下远程地址:

maxTrustedIndex 结果
[ Integer.MIN_VALUE,0] (无效,IllegalArgumentException初始化期间)
1 0.0.0.3
2 0.0.0.2
3 0.0.0.1
[4, Integer.MAX_VALUE] 0.0.0.1

以下示例显示了如何使用 Java 实现相同的配置:

示例 11.GatewayConfig.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")
)

权重路线谓词工厂

Weight路由谓词工厂有两个参数:和groupweight一个 int)。权重是按组计算的。以下示例配置权重路由谓词:

示例 12.application.yml

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

该路由会将约 80% 的流量转发到weighthigh.org,将约 20% 的流量转发到weightlow.org

GatewayFilter工厂

路由过滤器允许以某种方式修改传入的 HTTP 请求或传出的 HTTP 响应。路由过滤器的范围是特定的路由。Spring Cloud Gateway 包含许多内置的 GatewayFilter 工厂。

AddRequestHeader

AddRequestHeader GatewayFilter工厂采用name 和参数value。以下示例配置一个AddRequestHeaderGatewayFilter`:

示例 13.application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: add_request_header_route
        uri: https://example.org
        filters:
        - AddRequestHeader=X-Request-red, blue

此清单将X-Request-red:blue标头添加到所有匹配请求的下游请求标头中。

AddRequestHeader知道用于匹配路径或主机的 URI 变量。URI 变量可以在值中使用并在运行时扩展。以下示例配置AddRequestHeader GatewayFilter使用变量的 an:

示例 14.application.yml

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

AddRequestParameter

AddRequestParameter GatewayFilterFactory 采用andname参数value。以下示例配置一个AddRequestParameter GatewayFilter

示例 15.application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: add_request_parameter_route
        uri: https://example.org
        filters:
        - AddRequestParameter=red, blue

这将添加red=blue到所有匹配请求的下游请求的查询字符串中。

AddRequestParameter知道用于匹配路径或主机的 URI 变量。URI 变量可以在值中使用并在运行时扩展。以下示例配置AddRequestParameter GatewayFilter使用变量的 an:

示例 16.application.yml

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

AddResponseHeader

AddResponseHeader GatewayFilterFactory 采用andname参数value。以下示例配置一个AddResponseHeader GatewayFilter

示例 17.application.yml

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

这会将X-Response-Red:Blue标头添加到所有匹配请求的下游响应标头中。

AddResponseHeader知道用于匹配路径或主机的 URI 变量。URI 变量可以在值中使用并在运行时扩展。以下示例配置AddResponseHeader GatewayFilter使用变量的 an:

示例 18.application.yml

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

DedupeResponseHeader

DedupeResponseHeader GatewayFilter 工厂接受一个name参数和一个可选strategy参数。name可以包含以空格分隔的标题名称列表。以下示例配置了一个DedupeResponseHeader GatewayFilter

示例 19.application.yml

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

在网关 CORS 逻辑和下游逻辑都添加它们的情况下,这将删除重复值Access-Control-Allow-Credentials和响应标头。Access-Control-Allow-Origin

过滤器DedupeResponseHeader还接受一个可选strategy参数。接受的值为RETAIN_FIRST(默认)RETAIN_LAST、 和RETAIN_UNIQUE

Spring Cloud CircuitBreaker

Spring Cloud CircuitBreaker GatewayFilter 工厂使用 Spring Cloud CircuitBreaker API 将网关路由包装在断路器中。Spring Cloud CircuitBreaker 支持多个可与 Spring Cloud Gateway 一起使用的库。Spring Cloud 开箱即用地支持 Resilience4J。

要启用 Spring Cloud CircuitBreaker 过滤器,您需要放置spring-cloud-starter-circuitbreaker-reactor-resilience4j在类路径中。以下示例配置 Spring Cloud CircuitBreaker GatewayFilter

示例 20.application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: circuitbreaker_route
        uri: https://example.org
        filters:
        - CircuitBreaker=myCircuitBreaker

要配置断路器,请参阅您正在使用的底层断路器实现的配置。

Spring Cloud CircuitBreaker 过滤器也可以接受一个可选fallbackUri参数。目前,仅forward:支持方案化 URI。如果调用了fallback,则将请求转发到URI匹配的控制器。以下示例配置了这样的回退:

示例 21.application.yml

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

下面的清单在 Java 中做同样的事情:

例 22.Application.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();
}

/inCaseofFailureUseThis此示例在调用断路器回退时转发到URI。请注意,此示例还演示了(可选)Spring Cloud LoadBalancer 负载平衡(由lb目标 URI 上的前缀定义)。

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

示例 23.application.yml

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

在此示例中,网关应用程序中没有fallback端点或处理程序。但是,在另一个应用程序中有一个,在localhost:9994.

在请求被转发到回退的情况下,Spring Cloud CircuitBreaker Gateway 过滤器还提供了Throwable导致它的原因。它被添加到ServerWebExchange作为ServerWebExchangeUtils.CIRCUITBREAKER_EXECUTION_EXCEPTION_ATTR在网关应用程序中处理回退时可以使用的属性。

对于外部控制器/处理程序场景,可以添加带有异常详细信息的标头。

在状态代码上使断路器回退

在某些情况下,您可能希望根据从其包裹的路由返回的状态代码来触发断路器。断路器配置对象采用状态代码列表,如果返回将导致断路器跳闸。在设置要使断路器跳闸的状态代码时,您可以使用带有状态代码值的整数或HttpStatus枚举的字符串表示形式。

示例 24.application.yml

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"

例 25.Application.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();
}

FallbackHeaders

工厂允许您在转发到外部应用程序中FallbackHeaders的请求的标头中添加 Spring Cloud CircuitBreaker 执行异常详细信息,如以下场景所示:fallbackUri

示例 26.application.yml

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

在此示例中,在运行断路器时发生执行异常后,请求将被转发到fallback运行在 上的应用程序中的端点或处理程序localhost:9994。具有异常类型、消息和(如果可用)根本原因异常类型和消息的标头由FallbackHeaders过滤器添加到该请求。

您可以通过设置以下参数的值(显示为默认值)来覆盖配置中标头的名称:

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

有关断路器和网关的更多信息,请参阅Spring Cloud CircuitBreaker Factory 部分

MapRequestHeader

MapRequestHeader GatewayFilter工厂接受fromHeadertoHeader参数。它创建一个新的命名标头 ( ),并从传入的 http 请求中从toHeader现有的命名标头 ( ) 中提取值。fromHeader如果输入标头不存在,则过滤器没有影响。如果新的命名标头已经存在,则其值将使用新值进行扩充。以下示例配置了一个MapRequestHeader

示例 27.application.yml

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

这会将X-Request-Red:<values>标头添加到下游请求,其中包含来自传入 HTTP 请求Blue标头的更新值。

PrefixPath

工厂采用PrefixPath GatewayFilter单个prefix参数。以下示例配置了一个PrefixPath GatewayFilter

示例 28.application.yml

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

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

PreserveHostHeader

PreserveHostHeader GatewayFilter工厂没有参数。此过滤器设置路由过滤器检查的请求属性,以确定是否应发送原始主机头,而不是由 HTTP 客户端确定的主机头。以下示例配置了一个PreserveHostHeader GatewayFilter

示例 29.application.yml

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

RequestRateLimiter

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

此过滤器采用可选keyResolver参数和特定于速率限制器的参数(本节稍后描述)。

keyResolver是实现KeyResolver接口的bean。在配置中,使用 SpEL 按名称引用 bean。 #{@myKeyResolver}是一个引用名为 的 bean 的 SpEL 表达式myKeyResolver。以下清单显示了该KeyResolver界面:

示例 30.KeyResolver.java

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

KeyResolver接口让可插拔策略派生出限制请求的密钥。在未来的里程碑版本中,将会有一些KeyResolver实现。

的默认实现KeyResolverPrincipalNameKeyResolver,它PrincipalServerWebExchange和调用中检索Principal.getName()

默认情况下,如果KeyResolver找不到密钥,则拒绝请求。spring.cloud.gateway.filter.request-rate-limiter.deny-empty-key您可以通过设置(truefalse) 和spring.cloud.gateway.filter.request-rate-limiter.empty-key-status-code属性来调整此行为。

Redis RateLimiter

Redis 的实现基于在Stripe完成的工作。它需要使用spring-boot-starter-data-redis-reactiveSpring Boot 启动器。

使用的算法是令牌桶算法

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

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

redis-rate-limiter.requestedTokens属性是请求花费多少令牌。这是每个请求从存储桶中获取的令牌数,默认为1.

replenishRate通过在和中设置相同的值来实现稳定的速率burstCapacityburstCapacity通过设置高于可以允许临时突发replenishRate。在这种情况下,需要允许速率限制器在突发之间有一段时间(根据replenishRate),因为两个连续的突发将导致请求被丢弃(HTTP 429 - Too Many Requests)。以下清单配置了一个redis-rate-limiter

下面的速率限制1 request/s是通过设置replenishRate所需的请求数、requestedTokens以秒为单位的时间跨度以及 和burstCapacity的乘积来实现的replenishRaterequestedTokens例如设置replenishRate=1requestedTokens=60并将burstCapacity=60导致 的限制1 request/min

示例 32.application.yml

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

以下示例在 Java 中配置 KeyResolver:

示例 33. 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 表达式,它引用了一个名为 的 bean myRateLimiter。下面的清单定义了一个使用KeyResolver前面清单中定义的速率限制器:

示例 34.application.yml

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

RedirectTo

RedirectTo GatewayFilter工厂有两个参数,statusurl。参数应为status300 系列重定向 HTTP 代码,例如 301。url参数应为有效 URL。这是Location标头的值。对于相对重定向,您应该使用uri: no://op路由定义的 uri。以下清单配置了一个RedirectTo GatewayFilter

示例 35.application.yml

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

这将发送带有Location:https://acme.org标头的状态 302 以执行重定向。

RemoveRequestHeader

RemoveRequestHeader GatewayFilter工厂接受一个name参数。它是要删除的标头的名称。以下清单配置了一个RemoveRequestHeader GatewayFilter

示例 36.application.yml

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

这会在将X-Request-Foo标头发送到下游之前将其删除。

RemoveResponseHeader

RemoveResponseHeader GatewayFilter工厂接受一个name参数。它是要删除的标头的名称。以下清单配置了一个RemoveResponseHeader GatewayFilter

示例 37.application.yml

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

这将X-Response-Foo在返回给网关客户端之前从响应中删除标头。

要删除任何类型的敏感标头,您应该为您可能想要这样做的任何路由配置此过滤器。此外,您可以通过使用配置此过滤器一次spring.cloud.gateway.default-filters并将其应用于所有路由。

RemoveRequestParameter

RemoveRequestParameter GatewayFilter工厂接受一个name参数。它是要删除的查询参数的名称。以下示例配置了一个RemoveRequestParameter GatewayFilter

示例 38.application.yml

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

这将在将red参数发送到下游之前将其删除。

RewritePath

工厂接受一个RewritePath GatewayFilter路径regexp参数和一个replacement参数。这使用 Java 正则表达式以灵活的方式重写请求路径。以下清单配置了一个RewritePath GatewayFilter

示例 39.application.yml

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

对于 的请求路径/red/blue,这会将路径设置为/blue在发出下游请求之前。请注意,由于 YAML 规范,$应将其替换为。$\

RewriteLocationResponseHeader

RewriteLocationResponseHeader GatewayFilter工厂修改响应头的值,Location通常是为了摆脱后端特定的细节。它需要stripVersionModelocationHeaderNamehostValueprotocolsRegex参数。以下清单配置了一个RewriteLocationResponseHeader GatewayFilter

示例 40.application.yml

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

例如,对于 的请求, 的响应头值被重写为。POST api.example.com/some/object/name``Location``object-service.prod.example.net/v2/some/object/id``api.example.com/some/object/id

stripVersionMode参数具有以下可能的值:NEVER_STRIPAS_IN_REQUEST(默认)和ALWAYS_STRIP

  • NEVER_STRIP:版本不会被剥离,即使原始请求路径不包含版本。
  • AS_IN_REQUEST 仅当原始请求路径不包含版本时,才会剥离版本。
  • ALWAYS_STRIP 版本总是被剥离,即使原始请求路径包含版本。

hostValue参数(如果提供)用于替换host:port响应Location标头的部分。如果未提供,Host则使用请求标头的值。

protocolsRegex参数必须是有效的正则表达式String,协议名称与之匹配。如果不匹配,过滤器什么也不做。默认值为http|https|ftp|ftps.

RewriteResponseHeader

RewriteResponseHeader GatewayFilter工厂采用、nameregexp参数replacement。它使用 Java 正则表达式以灵活的方式重写响应标头值。以下示例配置了一个RewriteResponseHeader GatewayFilter

示例 41.application.yml

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

对于 的标头值,在发出下游请求后将/42?user=ford&password=omg!what&flag=true其设置为。由于 YAML 规范,/42?user=ford&password=***&flag=true您必须使用$\to 表示。$

SaveSession

工厂在将呼叫转发到下游之前SaveSession GatewayFilter强制执行WebSession::save操作。这在使用诸如带有惰性数据存储的Spring Session 之类的东西时特别有用,并且您需要确保在进行转发调用之前已保存会话状态。以下示例配置了一个:SaveSession GatewayFilter

示例 42.application.yml

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

如果您将Spring Security与 Spring Session 集成并希望确保安全详细信息已转发到远程进程,这很关键。

6.19。SecureHeaders GatewayFilter工厂_

根据这篇博SecureHeaders GatewayFilter文中的建议,工厂会在响应中添加一些标头。

添加了以下标题(显示为默认值):

  • 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
  • x-frame-options
  • x-content-type-options
  • referrer-policy
  • content-security-policy
  • x-download-options
  • x-permitted-cross-domain-policies

要禁用默认值,请spring.cloud.gateway.filter.secure-headers.disable使用逗号分隔值设置属性。以下示例显示了如何执行此操作:

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

6.20。SetPath GatewayFilter工厂_

SetPath GatewayFilter工厂采用路径参数template。它通过允许路径的模板化段提供了一种操作请求路径的简单方法。这使用来自 Spring Framework 的 URI 模板。允许多个匹配段。以下示例配置了一个SetPath GatewayFilter

示例 43.application.yml

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

对于 的请求路径/red/blue,这会将路径设置为/blue在发出下游请求之前。

6.21。SetRequestHeader GatewayFilter工厂_

SetRequestHeader GatewayFilter工厂接受namevalue参数。以下清单配置了一个SetRequestHeader GatewayFilter

示例 44.application.yml

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

GatewayFilter将替换(而不是添加)具有给定名称的所有标题。因此,如果下游服务器以 响应X-Request-Red:1234,这将被替换X-Request-Red:Blue为下游服务将接收的内容。

SetRequestHeader知道用于匹配路径或主机的 URI 变量。URI 变量可以在值中使用并在运行时扩展。以下示例配置SetRequestHeader GatewayFilter使用变量的 an:

示例 45.application.yml

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

6.22。SetResponseHeader GatewayFilter工厂_

SetResponseHeader GatewayFilter工厂接受namevalue参数。以下清单配置了一个SetResponseHeader GatewayFilter

示例 46.application.yml

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

此 GatewayFilter 用给定名称替换(而不是添加)所有标头。因此,如果下游服务器以 响应 ,则将其X-Response-Red:1234替换为X-Response-Red:Blue,这是网关客户端将收到的。

SetResponseHeader知道用于匹配路径或主机的 URI 变量。URI 变量可以在值中使用,并将在运行时扩展。以下示例配置SetResponseHeader GatewayFilter使用变量的 an:

示例 47.application.yml

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

6.23。SetStatus GatewayFilter工厂_

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

示例 48.application.yml

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

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

您可以将其配置为SetStatus GatewayFilter在响应的标头中从代理请求返回原始 HTTP 状态代码。如果配置了以下属性,则标头将添加到响应中:

示例 49.application.yml

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

StripPrefix

StripPrefix GatewayFilter工厂采用一个参数,parts. 该parts参数指示在将请求发送到下游之前要从请求中剥离的路径中的部分数。以下清单配置了一个StripPrefix GatewayFilter

示例 50.application.yml

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

当通过网关向发出请求时/name/blue/red,向 发出的请求nameservice看起来像nameservice/red

重试GatewayFilter

Retry GatewayFilter工厂支持以下参数:

  • retries:应该尝试的重试次数。
  • statuses:应该重试的HTTP状态码,用 表示org.springframework.http.HttpStatus
  • methods:应该重试的HTTP方法,用 表示org.springframework.http.HttpMethod
  • series:要重试的一系列状态码,用 表示org.springframework.http.HttpStatus.Series
  • exceptions:应重试的抛出异常列表。
  • backoff:为重试配置的指数退避。重试在 的退避间隔后执行firstBackoff * (factor ^ n),其中n是迭代。如果maxBackoff已配置,则应用的最大退避限制为maxBackoff. 如果basedOnPreviousValue为真,则使用 计算退避prevBackoff * factor

Retry如果启用,则为过滤器配置以下默认值:

  • retries: 三倍
  • series: 5XX 系列
  • methods: 获取方法
  • exceptions:IOExceptionTimeoutException
  • backoff: 禁用

以下清单配置了 Retry GatewayFilter

示例 51.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
            methods: GET,POST
            backoff:
              firstBackoff: 10ms
              maxBackoff: 50ms
              factor: 2
              basedOnPreviousValue: false
使用带有forward:前缀 URL 的重试过滤器时,应仔细编写目标端点,以便在发生错误时不会执行任何可能导致将响应发送到客户端并提交的操作。例如,如果目标端点是带注释的控制器,则目标控制器方法不应返回ResponseEntity错误状态代码。相反,它应该抛出Exception或发出错误信号(例如,通过Mono.error(ex)返回值),重试过滤器可以配置为通过重试来处理。
将重试过滤器与任何带有正文的 HTTP 方法一起使用时,正文将被缓存,并且网关将受到内存限制。正文缓存在由 定义的请求属性中ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR。对象的类型是 a org.springframework.core.io.buffer.DataBuffer

可以使用单个statusand来添加简化的“快捷方式”表示法method

下面两个例子是等价的:

示例 52.application.yml

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

6.26。RequestSize GatewayFilter工厂_

当请求大小大于允许的限制时,RequestSize GatewayFilter工厂可以限制请求到达下游服务。过滤器接受一个maxSize参数。类型,因此maxSize is aDataSize值可以定义为一个数字,后跟一个可选的DataUnit后缀,例如“KB”或“MB”。字节的默认值为“B”。它是以字节为单位定义的请求的允许大小限制。以下清单配置了一个RequestSizeGatewayFilter`:

示例 53.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工厂将响应状态设置为413 Payload Too Large附加标头。errorMessage以下示例显示了这样一个errorMessage

errorMessage` : `Request size is larger than permissible limit. Request size is 6.0 MB where permissible limit is 5.0 MB
如果未在路由定义中作为过滤器参数提供,则默认请求大小设置为 5 MB。

6.27。SetRequestHostHeader GatewayFilter工厂_

在某些情况下,可能需要覆盖主机标头。在这种情况下,SetRequestHostHeader GatewayFilter工厂可以用指定的值替换现有的主机头。过滤器接受一个host参数。以下清单配置了一个SetRequestHostHeader GatewayFilter

示例 54.application.yml

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

工厂将主机头的SetRequestHostHeader GatewayFilter值替换为example.org.

6.28。修改请求体GatewayFilter工厂

您可以使用ModifyRequestBody过滤器过滤器在网关将请求主体发送到下游之前对其进行修改。

只能使用 Java DSL 配置此过滤器。

以下清单显示了如何修改请求正文GatewayFilter

@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;
    }
}
如果请求没有正文,RewriteFilter则将通过nullMono.empty()应返回以在请求中分配缺少的正文。

6.29。修改响应体GatewayFilter工厂

您可以使用ModifyResponseBody过滤器在将响应正文发送回客户端之前对其进行修改。

只能使用 Java DSL 配置此过滤器。

以下清单显示了如何修改响应正文GatewayFilter

@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();
}
如果响应没有正文,RewriteFilter则将通过nullMono.empty()应返回以在响应中分配缺少的正文。

6.30。令牌中继GatewayFilter工厂

令牌中继是 OAuth2 消费者充当客户端并将传入令牌转发给传出资源请求的地方。消费者可以是纯客户端(如 SSO 应用程序)或资源服务器。

Spring Cloud Gateway 可以将 OAuth2 访问令牌向下游转发到它所代理的服务。要将此功能添加到网关,您需要添加 TokenRelayGatewayFilterFactory如下内容:

应用程序.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();
}

或这个

应用程序.yaml

spring:
  cloud:
    gateway:
      routes:
      - id: resource
        uri: http://localhost:9000
        predicates:
        - Path=/resource
        filters:
        - TokenRelay=

并且它将(除了登录用户并获取令牌之外)将身份验证令牌传递给下游的服务(在这种情况下 /resource)。

要为 Spring Cloud Gateway 启用此功能,请添加以下依赖项

  • org.springframework.boot:spring-boot-starter-oauth2-client

它是如何工作的?{githubmaster}/src/main/java/org/springframework/cloud/gateway/security/TokenRelayGatewayFilterFactory.java[filter] 从当前经过身份验证的用户中提取访问令牌,并将其放入下游请求的请求标头中。

有关完整的工作示例,请参阅此项目

仅当设置了将触发创建beanTokenRelayGatewayFilterFactory的适当属性时才会创建bean。 spring.security.oauth2.client.*``ReactiveClientRegistrationRepository
ReactiveOAuth2AuthorizedClientServiceused by 的默认实现使用TokenRelayGatewayFilterFactory 内存数据存储。ReactiveOAuth2AuthorizedClientService 如果您需要更强大的解决方案, 您将需要提供自己的实现。

6.31。CacheRequestBody GatewayFilter工厂_

有一定的情况需要读取body。由于请求体流只能读取一次,所以我们需要缓存请求体。您可以使用CacheRequestBody过滤器在请求正文发送到下游之前缓存请求正文并从 exchagne 属性获取正文。

以下清单显示了如何缓存请求正文GatewayFilter

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

示例 55.application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: cache_request_body_route
        uri: lb://downstream
        predicates:
        - Path=/downstream/**
        filters:
        - name: CacheRequestBody
          args:
            bodyClass: java.lang.String

CacheRequestBody将提取请求正文并将其转换为正文类(例如java.lang.String,在前面的示例中定义)。然后将其放置在 中,ServerWebExchange.getAttributes()并使用 中定义的键ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR

此过滤器仅适用于 http 请求(包括 https)。

6.32。默认过滤器

要添加过滤器并将其应用于所有路由,您可以使用spring.cloud.gateway.default-filters. 此属性采用过滤器列表。以下清单定义了一组默认过滤器:

示例 56.application.yml

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

全局过滤器

GlobalFilter接口具有与 相同的签名GatewayFilter。这些是有条件地应用于所有路由的特殊过滤器。

组合全局过滤器和GatewayFilter排序

当请求与路由匹配时,过滤 Web 处理程序会将 的所有实例GlobalFilter和所有特定于路由的实例添加GatewayFilter到过滤器链中。这个组合的过滤器链是按org.springframework.core.Ordered接口排序的,你可以通过实现getOrder()方法来设置。

由于 Spring Cloud Gateway 区分过滤器逻辑执行的“前”和“后”阶段(请参阅它的工作原理),具有最高优先级的过滤器是“前”阶段的第一个和“后”阶段的最后一个 -阶段。

以下清单配置了一个过滤器链:

例 57.ExampleConfiguration.java

@Bean
public GlobalFilter customFilter() {
    return new CustomGlobalFilter();
}

public class CustomGlobalFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("custom global filter");
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -1;
    }
}

转发路由过滤器

ForwardRoutingFilterexchange 属性中查找 URI ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR。如果 URL 有一个forward方案(例如forward:///localendpoint),它使用 SpringDispatcherHandler来处理请求。请求 URL 的路径部分被转发 URL 中的路径覆盖。未修改的原始 URL 将附加到ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR属性中的列表中。

ReactiveLoadBalancerClientFilter

ReactiveLoadBalancerClientFilter名为 的交换属性中查找 URI ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR。如果 URL 有一个lb方案(例如lb://myservice),它使用 Spring CloudReactorLoadBalancer将名称(在本例中)解析为myservice实际的主机和端口,并替换同一属性中的 URI。未修改的原始 URL 将附加到ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR属性中的列表中。过滤器还查看ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR属性以查看它是否等于lb。如果是这样,则适用相同的规则。以下清单配置了一个ReactiveLoadBalancerClientFilter

示例 58.application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: myRoute
        uri: lb://service
        predicates:
        - Path=/service/**

Netty 路由过滤器

如果位于ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR交换属性中的 URL 具有httporhttps方案,则 Netty 路由过滤器运行。它使用 NettyHttpClient发出下游代理请求。响应被放入ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR交换属性中,以供稍后的过滤器使用。(还有一个WebClientHttpRoutingFilter执行相同功能但不需要 Netty 的实验。)

Netty 写响应过滤器

如果交换属性中NettyWriteResponseFilter有 Netty HttpClientResponse,则运行。ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR它在所有其他过滤器完成后运行,并将代理响应写回网关客户端响应。(还有一个WebClientWriteResponseFilter执行相同功能但不需要 Netty 的实验。)

RouteToRequestUrl

如果交换属性中有Route对象,则运行。它基于请求 URI 创建一个新的 URI,但使用对象的 URI 属性进行更新。新的 URI 被放置在exchange 属性中。ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR``RouteToRequestUrlFilter``Route``ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR

如果 URI 具有方案前缀,例如lb:ws://serviceidlb则从 URI 中剥离方案并放置在ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR过滤器链中以供稍后使用。

Websocket 路由过滤器

如果位于ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTRexchange 属性中的 URL 具有wsorwss方案,则 websocket 路由过滤器运行。它使用 Spring WebSocket 基础设施向下游转发 websocket 请求。

您可以通过在 URI 前加上前缀来负载平衡 websocket lb,例如lb:ws://serviceid.

如果你使用SockJS作为普通 HTTP 的后备,你应该配置一个普通的 HTTP 路由以及 websocket 路由。

以下清单配置了一个 websocket 路由过滤器:

示例 59.application.yml

spring:
  cloud:
    gateway:
      routes:
      # SockJS route
      - id: websocket_sockjs_route
        uri: http://localhost:3001
        predicates:
        - Path=/websocket/info/**
      # Normal Websocket route
      - id: websocket_route
        uri: ws://localhost:3001
        predicates:
        - Path=/websocket/**

网关指标过滤器

要启用网关指标,请将 spring-boot-starter-actuator 添加为项目依赖项。然后,默认情况下,只要该属性spring.cloud.gateway.metrics.enabled未设置为,网关指标过滤器就会运行falsespring.cloud.gateway.requests此过滤器添加一个使用以下标签命名的计时器指标:

  • routeId: 路由ID。
  • routeUri:API 路由到的 URI。
  • outcome:结果,按HttpStatus.Series分类。
  • status:返回给客户端的请求的HTTP状态。
  • httpStatusCode:返回给客户端的请求的 HTTP 状态。
  • httpMethod:用于请求的 HTTP 方法。

此外,通过该属性spring.cloud.gateway.metrics.tags.path.enabled(默认设置为 false),您可以使用标签激活额外的指标:

  • path:请求的路径。

然后可以从这些指标中提取/actuator/metrics/spring.cloud.gateway.requests并轻松与 Prometheus 集成以创建Grafana 仪表板

要启用 prometheus 端点,请添加micrometer-registry-prometheus为项目依赖项。

将交换标记为已路由

网关路由 a 后,它通过添加 交换属性将该交换ServerWebExchange标记为“已路由” 。gatewayAlreadyRouted一旦请求被标记为已路由,其他路由过滤器将不会再次路由该请求,实质上是跳过过滤器。您可以使用一些便捷的方法将交换标记为已路由或检查交换是否已被路由。

  • ServerWebExchangeUtils.isAlreadyRouted获取一个ServerWebExchange对象并检查它是否已被“路由”。
  • ServerWebExchangeUtils.setAlreadyRouted获取一个ServerWebExchange对象并将其标记为“已路由”。

HttpHeadersFilters

HttpHeadersFilters 在将请求发送到下游之前应用于请求,例如在NettyRoutingFilter.

转发标头过滤器

Forwarded头过滤器创建一个Forwarded标头以发送到下游服务。它将Host当前请求的标头、方案和端口添加到任何现有Forwarded标头。

RemoveHopByHop 标头过滤器

RemoveHopByHop头过滤器从转发的请求中删除标头。删除的默认标头列表来自IETF

默认删除的标题是:

  • 联系
  • 活着
  • 代理验证
  • 代理授权
  • TE
  • 预告片
  • 传输编码
  • 升级

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

XForwarded 标头过滤器

XForwarded头过滤器创建各种X-Forwarded-*标头以发送到下游服务。它使用Host当前请求的标头、方案、端口和路径来创建各种标头。

可以通过以下布尔属性控制单个标题的创建(默认为 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

附加多个标题可以由以下布尔属性控制(默认为 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 和 SSL

网关可以通过遵循通常的 Spring 服务器配置来监听 HTTPS 上的请求。以下示例显示了如何执行此操作:

例 60.application.yml

server:
  ssl:
    enabled: true
    key-alias: scg
    key-store-password: scg1234
    key-store: classpath:scg-keystore.p12
    key-store-type: PKCS12

您可以将网关路由路由到 HTTP 和 HTTPS 后端。如果您要路由到 HTTPS 后端,则可以使用以下配置将网关配置为信任所有下游证书:

示例 61.application.yml

spring:
  cloud:
    gateway:
      httpclient:
        ssl:
          useInsecureTrustManager: true

使用不安全的信任管理器不适合生产。对于生产部署,您可以使用一组已知证书配置网关,它可以使用以下配置信任这些证书:

示例 62.application.yml

spring:
  cloud:
    gateway:
      httpclient:
        ssl:
          trustedX509Certificates:
          - cert1.pem
          - cert2.pem

如果 Spring Cloud Gateway 没有配置受信任的证书,则使用默认的信任存储(您可以通过设置javax.net.ssl.trustStore系统属性来覆盖它)。

TLS 握手

网关维护一个客户端池,用于路由到后端。通过 HTTPS 进行通信时,客户端会启动 TLS 握手。许多超时与此握手相关。您可以配置这些超时,可以按如下方式配置(显示默认值):

示例 63.application.yml

spring:
  cloud:
    gateway:
      httpclient:
        ssl:
          handshake-timeout-millis: 10000
          close-notify-flush-timeout-millis: 3000
          close-notify-read-timeout-millis: 0

配置

Spring Cloud Gateway 的配置由RouteDefinitionLocator实例集合驱动。以下清单显示了RouteDefinitionLocator接口的定义:

示例 64.RouteDefinitionLocator.java

public interface RouteDefinitionLocator {
    Flux<RouteDefinition> getRouteDefinitions();
}

默认情况下,PropertiesRouteDefinitionLocator使用 Spring Boot 的@ConfigurationProperties机制加载属性。

早期的配置示例都使用使用位置参数而不是命名参数的快捷表示法。下面两个例子是等价的:

示例 65.application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: setstatus_route
        uri: https://example.org
        filters:
        - name: SetStatus
          args:
            status: 401
      - id: setstatusshortcut_route
        uri: https://example.org
        filters:
        - SetStatus=401

对于网关的某些用途,属性就足够了,但某些生产用例受益于从外部源(例如数据库)加载配置。未来的里程碑版本将具有RouteDefinitionLocator基于 Spring Data Repositories 的实现,例如 Redis、MongoDB 和 Cassandra。

RouteDefinition 指标

要启用RouteDefinition指标,请将 spring-boot-starter-actuator 添加为项目依赖项。然后,默认情况下,只要该属性spring.cloud.gateway.metrics.enabled设置为,这些指标就可用true。将添加一个名为的量规度量spring.cloud.gateway.routes.count,其值为RouteDefinitions. 该指标可从/actuator/metrics/spring.cloud.gateway.routes.count.

路由元数据配置

您可以使用元数据为每个路由配置附加参数,如下所示:

示例 66.application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: route_with_metadata
        uri: https://example.org
        metadata:
          optionName: "OptionValue"
          compositeObject:
            name: "value"
          iAmNumber: 1

您可以从交换中获取所有元数据属性,如下所示:

Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
// get all metadata properties
route.getMetadata();
// get a single metadata property
route.getMetadata(someKey);

Http超时配置

可以为所有路由配置 Http 超时(响应和连接),并为每个特定路由覆盖。

全局超时

要配置全局 http 超时:
connect-timeout必须以毫秒为单位指定。
response-timeout必须指定为 java.time.Duration

全局 http 超时示例

spring:
  cloud:
    gateway:
      httpclient:
        connect-timeout: 1000
        response-timeout: 5s

每条路由超时

要配置每条路由超时:
connect-timeout必须以毫秒为单位指定。
response-timeout必须以毫秒为单位指定。

通过配置进行每条路由 http 超时配置

      - id: per_route_timeouts
        uri: https://example.org
        predicates:
          - name: Path
            args:
              pattern: /delay/{timeout}
        metadata:
          response-timeout: 200
          connect-timeout: 200

使用 Java DSL 的每条路由超时配置

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

response-timeout具有负值的 per-route将禁用全局response-timeout值。

      - id:per_route_timeouts
        网址:https://example.org
        谓词:
          - 名称:路径
            参数:
              模式:/延迟/{超时}
        元数据:
          响应超时:-1

流畅的 Java 路由 API

为了允许在 Java 中进行简单配置,RouteLocatorBuilderbean 包含一个流式 API。下面的清单显示了它是如何工作的:

例 67.GatewaySampleApplication.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();
}

这种风格还允许更多的自定义谓词断言。bean定义的谓词RouteDefinitionLocator使用逻辑组合and。通过使用 fluent Java API,您可以在类上使用and()or()negate()运算符Predicate

路线DiscoveryClient定义定位器

您可以将网关配置为基于在DiscoveryClient兼容服务注册表中注册的服务创建路由。

要启用此功能,请设置spring.cloud.gateway.discovery.locator.enabled=true并确保DiscoveryClient实现(例如 Netflix Eureka、Consul 或 Zookeeper)在类路径上并启用。

DiscoveryClient为路由配置谓词和过滤器

默认情况下,网关为使用DiscoveryClient.

默认谓词是使用模式定义的路径谓词/serviceId/**,其中serviceId是来自DiscoveryClient.

默认过滤器是带有正则表达式/serviceId/?(?<remaining>.*)和替换的重写路径过滤器/${remaining}。这会在请求被发送到下游之前从路径中去除服务 ID。

如果要自定义DiscoveryClient路由使用的谓词或过滤器,请设置spring.cloud.gateway.discovery.locator.predicates[x]spring.cloud.gateway.discovery.locator.filters[y]。这样做时,如果要保留该功能,则需要确保包含前面显示的默认谓词和过滤器。以下示例显示了它的样子:

示例 68.application.properties

spring.cloud.gateway.discovery.locator.predicates[0].name:路径
spring.cloud.gateway.discovery.locator.predicates[0].args[pattern]: "'/'+serviceId+'/**'"
spring.cloud.gateway.discovery.locator.predicates[1].name:主机
spring.cloud.gateway.discovery.locator.predicates[1].args[pattern]: "'**.foo.com'"
spring.cloud.gateway.discovery.locator.filters[0].name:断路器
spring.cloud.gateway.discovery.locator.filters[0].args[name]: serviceId
spring.cloud.gateway.discovery.locator.filters[1].name:重写路径
spring.cloud.gateway.discovery.locator.filters[1].args[regexp]: "'/' + serviceId + '/?(?<remaining>.*)'"
spring.cloud.gateway.discovery.locator.filters[1].args[replacement]: "'/${remaining}'"

Reactor Netty 访问日志eference/html/#reactor-netty-access-logs)

要启用 Reactor Netty 访问日志,请设置-Dreactor.netty.http.server.accessLogEnabled=true.

您可以将日志记录系统配置为具有单独的访问日志文件。以下示例创建一个 Logback 配置:

例 69.logback.xml

    <appender name="accessLog" class="ch.qos.logback.core.FileAppender">
        <file>access_log.log</file>
        <encoder>
            <pattern>%msg%n</pattern>
        </encoder>
    </appender>
    <appender name="async" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="accessLog" />
    </appender>

    <logger name="reactor.netty.http.server.AccessLog" level="INFO" additivity="false">
        <appender-ref ref="async"/>
    </logger>

CORS配置

您可以配置网关来控制 CORS 行为。“全局” CORS 配置是 URL 模式到Spring FrameworkCorsConfiguration的映射。以下示例配置 CORS:

例 70.application.yml

spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            allowedOrigins: "https://docs.spring.io"
            allowedMethods:
            - GET

在前面的示例中,允许来自docs.spring.io所有 GET 请求路径的请求的 CORS 请求。

要为某些网关路由谓词未处理的请求提供相同的 CORS 配置,请将spring.cloud.gateway.globalcors.add-to-simple-url-handler-mapping属性设置为true. 当您尝试支持 CORS 预检请求并且您的路由谓词未评估为时,true这很有用,因为 HTTP 方法是options.

监控器 API

/gateway驱动器的端点,您可以监视和Spring的云网关应用程序进行交互。要远程访问,必须在应用程序属性中启用通过 HTTP 或 JMX 公开端点。以下清单显示了如何执行此操作:

示例 71.application.properties

management.endpoint.gateway.enabled=true # default value
management.endpoints.web.exposure.include=gateway

15.1. 详细执行器格式

Spring Cloud Gateway 中添加了一种新的、更详细的格式。它为每个路由添加了更多详细信息,让您可以查看与每个路由关联的谓词和过滤器以及任何可用配置。以下示例配置/actuator/gateway/routes

[
  {
    "predicate": "(Hosts: [**.addrequestheader.org] && Paths: [/headers], match trailing slash: true)",
    "route_id": "add_request_header_test",
    "filters": [
      "[[AddResponseHeader X-Response-Default-Foo = 'Default-Bar'], order = 1]",
      "[[AddRequestHeader X-Request-Foo = 'Bar'], order = 1]",
      "[[PrefixPath prefix = '/httpbin'], order = 2]"
    ],
    "uri": "lb://testservice",
    "order": 0
  }
]

默认情况下启用此功能。要禁用它,请设置以下属性:

示例 72.application.properties

spring.cloud.gateway.actuator.verbose.enabled=false

这将true在未来的版本中默认使用。

15.2. 检索路由过滤器

本节详细介绍如何检索路由过滤器,包括:

15.2.1. 全局过滤器

要检索应用于所有路由的全局过滤器GET,请向/actuator/gateway/globalfilters. 生成的响应类似于以下内容:

{
  “org.spring framework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter@77856cc5 ”:10100,
  “o rg.springframework.cloud.gateway.filter.RouteToRequestUrlFilter@4f6fd101 ”:10000,
  “或g.springframework.cloud.gateway.filter.NettyWriteResponseFilter@32d22650 ”:-1,
  " org.springframework.cloud.gateway.filter.ForwardRoutingFilter@10 6459d9": 2147483647,
  “ org.springframework.cloud.gateway.filter.NettyRoutingFilter@1fbd 5e0”:2147483647,
  " org.springframework.cloud.gateway.filter.ForwardPathFilter@33a71 d23": 0,
  “org.s pringframework.cloud.gateway.filter.AdaptCachedBodyGlobalFilter@135064ea ”:2147483637,
  “ org.springframework.cloud.gateway.filter.WebsocketRoutingFilter@23c05889 ”:2147483646
}

响应包含已到位的全局过滤器的详细信息。对于每个全局过滤器,都有过滤器对象的字符串表示形式(例如,org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter@77856cc5)和过滤器链中的相应顺序。}

15.2.2. 路由过滤器

要检索应用于路由的GatewayFilter工厂GET请向/actuator/gateway/routefilters. 生成的响应类似于以下内容:

{
  “[ AddRequestHeaderGatewayFilterFactory@570ed9c configClass = AbstractNameValueGatewayFilterFactory.NameValueConfig]”:空,
  “[ SecureHeadersGatewayFilterFactory@fceab5d configClass = Object]”:空,
  “[ SaveSessionGatewayFilterFactory@4449b273 configClass = Object]”:空
}

响应包含GatewayFilter应用于任何特定路由的工厂的详细信息。对于每个工厂,都有对应对象的字符串表示形式(例如,[SecureHeadersGatewayFilterFactory@fceab5d configClass = Object])。请注意,该null值是由于端点控制器的实现不完整,因为它试图设置对象在过滤器链中的顺序,这不适用于GatewayFilter工厂对象。

15.3. 刷新路由缓存

要清除路由缓存,POST请向/actuator/gateway/refresh. 该请求返回没有响应正文的 200。

15.4. 检索网关中定义的路由

要检索网关中定义的路由,GET请向/actuator/gateway/routes. 生成的响应类似于以下内容:

[{
  "route_id": "first_route",
  “路由对象”:{
    “断言”: “org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory $$ LAMBDA $ 432/ 1736826640 @ 1e9d7e7d ”
    “过滤器”:[
      “OrderedGatewayFilter {代表= org.springframework.cloud.gateway.filter.factory.PreserveHostHeaderGatewayFilterFactory $$ LAMBDA $ 436/ 674480275 @ 6631ef72 ,为了= 0}”
    ]
  },
  “订单”:0
},
{
  "route_id": "second_route",
  “路由对象”:{“谓词
    ”:“org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory$$Lambda$432/1736826640@cd8d298 ”,
    “过滤器”:[]
  },
  “订单”:0
}]

响应包含网关中定义的所有路由的详细信息。下表描述了响应的每个元素(每个元素都是一个路由)的结构:

小路 类型 描述
route_id 细绳 路线标识。
route_object.predicate 目的 路由谓词。
route_object.filters 大批 GatewayFilter工厂申请了这条路线。
order 数字 路线顺序。

15.5。检索有关特定路线的信息

要检索有关单个路由的信息,GET请向/actuator/gateway/routes/{id}(例如,/actuator/gateway/routes/first_route)发出请求。生成的响应类似于以下内容:

{
  "id": "first_route",
  “谓词”:[{
    “名称”:“路径”,
    "args": {"_genkey_0":"/first"}
  }],
  “过滤器”:[],
  "uri": "https://www.uri-destination.org",
  “订单”:0
}

下表描述了响应的结构:

小路 类型 描述
id 细绳 路线标识。
predicates 大批 路由谓词的集合。每个项目定义给定谓词的名称和参数。
filters 大批 应用于路由的过滤器集合。
uri 细绳 路由的目标 URI。
order 数字 路线顺序。

15.6。创建和删除特定路线

要创建路由,请使用指定路由字段的 JSON 正文POST发出请求(请参阅检索有关特定路由的信息)。/gateway/routes/{id_route_to_create}

要删除路线,DELETE请向/gateway/routes/{id_route_to_delete}.

15.7. 回顾:所有端点的列表

下表总结了 Spring Cloud Gateway 执行器端点(请注意,每个端点都有/actuator/gateway作为基本路径):

ID HTTP 方法 描述
globalfilters 得到 显示应用于路由的全局过滤器列表。
routefilters 得到 显示GatewayFilter应用于特定路线的工厂列表。
refresh 邮政 清除路由缓存。
routes 得到 显示网关中定义的路由列表。
routes/{id} 得到 显示有关特定路线的信息。
routes/{id} 邮政 向网关添加新路由。
routes/{id} 删除 从网关中删除现有路由。

15.8. 在多个网关实例之间共享路由

Spring Cloud Gateway 提供了两种RouteDefinitionRepository实现。第一个是 InMemoryRouteDefinitionRepository只存在于一个网关实例的内存中。这种类型的存储库不适合跨多个网关实例填充路由。

为了在 Spring Cloud Gateway 实例的集群*享路由,RedisRouteDefinitionRepository可以使用。要启用这种存储库,必须将以下属性设置为 true:spring.cloud.gateway.redis-route-definition-repository.enabled 与 RedisRateLimiter Filter Factory 类似,它需要使用 spring-boot-starter-data-redis-reactive Spring Boot 启动器。

故障排除

本节介绍使用 Spring Cloud Gateway 时可能出现的常见问题。

16.1. 日志级别

以下记录器可能在DEBUGTRACE级别包含有价值的故障排除信息:

  • org.springframework.cloud.gateway
  • org.springframework.http.server.reactive
  • org.springframework.web.reactive
  • org.springframework.boot.autoconfigure.web
  • reactor.netty
  • redisratelimiter

16.2. 窃听

Reactor NettyHttpClient可以HttpServer启用窃听。与将reactor.netty日志级别设置为DEBUG或结合使用时TRACE,它可以记录信息,例如通过网络发送和接收的标头和正文。要启用窃听,请分别为和设置spring.cloud.gateway.httpserver.wiretap=true或。spring.cloud.gateway.httpclient.wiretap=true``HttpServer``HttpClient

开发者指南

这些是编写网关的一些自定义组件的基本指南。

17.1. 编写自定义路由谓词工厂

为了编写路由谓词,您需要将其实现RoutePredicateFactory为 bean。有一个AbstractRoutePredicateFactory可以扩展的抽象类。

MyRoutePredicateFactory.java

@Component
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config> {

    public MyRoutePredicateFactory() {
        super(Config.class);
    }

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        // grab configuration from Config object
        return exchange -> {
            //grab the request
            ServerHttpRequest request = exchange.getRequest();
            //take information from the request to see if it
            //matches configuration.
            return matches(config, request);
        };
    }

    public static class Config {
        //Put the configuration properties for your filter here
    }

}

17.2. 编写自定义 GatewayFilter 工厂

要编写GatewayFilter,您必须将其实现GatewayFilterFactory为 bean。您可以扩展一个名为AbstractGatewayFilterFactory. 以下示例显示了如何执行此操作:

示例 73. PreGatewayFilterFactory.java

@Component
public class PreGatewayFilterFactory extends AbstractGatewayFilterFactory<PreGatewayFilterFactory.Config> {

    public PreGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        // grab configuration from Config object
        return (exchange, chain) -> {
            //If you want to build a "pre" filter you need to manipulate the
            //request before calling chain.filter
            ServerHttpRequest.Builder builder = exchange.getRequest().mutate();
            //use builder to manipulate the request
            return chain.filter(exchange.mutate().request(builder.build()).build());
        };
    }

    public static class Config {
        //Put the configuration properties for your filter here
    }

}

PostGatewayFilterFactory.java

@Component
public class PostGatewayFilterFactory extends AbstractGatewayFilterFactory<PostGatewayFilterFactory.Config> {

    public PostGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        // grab configuration from Config object
        return (exchange, chain) -> {
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                ServerHttpResponse response = exchange.getResponse();
                //Manipulate the response in some way
            }));
        };
    }

    public static class Config {
        //Put the configuration properties for your filter here
    }

}

17.2.1. 在配置中命名自定义过滤器和引用

自定义过滤器类名应以GatewayFilterFactory.

例如,要引用Something配置文件中命名的过滤器,该过滤器必须位于名为SomethingGatewayFilterFactory.

可以创建一个不带 GatewayFilterFactory后缀的网关过滤器,例如class AnotherThing. 此过滤器可以AnotherThing在配置文件中引用。这不是受支持的命名约定,并且在将来的版本中可能会删除此语法。请更新过滤器名称以使其符合要求。

17.3. 编写自定义全局过滤器

要编写自定义全局过滤器,您必须GlobalFilter将接口实现为 bean。这会将过滤器应用于所有请求。

以下示例分别显示了如何设置全局前置和后置过滤器:

@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();
}
上一篇:容器服务Kubernetes(ACK)及相关云环境几次故障和问题排查记录


下一篇:Java内存模型FAQ(五)旧的内存模型有什么问题?