程序员L札记

V1

2022/04/21阅读:39主题:橙心

最新Spring Cloud Gateway中文文档(三)

spring cloud gateway版本3.1.1


Global Filters

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

此接口及其用法可能会在未来的里程碑版本中发生变化。

Combined Global Filter and GatewayFilter Ordering

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

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

下面的列表配置了一个过滤器链:

Example 58. ExampleConfiguration.java

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

public class CustomGlobalFilter implements GlobalFilterOrdered {

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

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

ForwardRoutingFilter

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

ReactiveLoadBalancerClientFilter

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

Example 59. application.yml

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

默认情况下,当 ReactorLoadBalancer 找不到服务实例时,会返回 503。您可以通过设置 spring.cloud.gateway.loadbalancer.use404=true 来配置网关以返回 404。

从 ReactiveLoadBalancerClientFilter 返回的 ServiceInstance 的 isSecure 值会覆盖向网关发出的请求中指定的方案。例如,如果请求通过 HTTPS 进入网关,但 ServiceInstance 指示它不安全,则通过 HTTP 发出下游请求。相反的情况也可以适用。但是,如果在网关配置中为路由指定了 GATEWAY_SCHEME_PREFIX_ATTR,则会去除前缀,并且路由 URL 的结果方案会覆盖 ServiceInstance 配置。

网关支持所有的LoadBalancer特性。您可以在Spring Cloud Commons文档中阅读更多关于它们的信息。

NettyRoutingFilter

如果根据ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR属性从exchange中获取的 URL 具有 http 或 https scheme,则 NettyRoutingFilter运行。它使用 Netty HttpClient 发出下游代理请求。响应放在 exchange ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR 属性中,以供以后的过滤器使用。 (还有一个实验性的 WebClientHttpRoutingFilter 执行相同的功能但不需要 Netty。)

NettyWriteResponseFilter

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

RouteToRequestUrlFilter

如果根据ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR 属性从exchange中获得 Route 对象,则 RouteToRequestUrlFilter 运行。它基于请求 URI 创建一个新的 URI,但使用 Route 对象的 URI 属性进行更新。新 URI 放置在 exchange ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 属性中。

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

WebsocketRoutingFilter

如果根据 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 属性从exchange中获得的 URL 具有 ws 或 wss scheme,则 WebsocketRoutingFilter运行。它使用 Spring WebSocket 基础设施向下游转发 websocket 请求。

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

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

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

Example 60. 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/**

GatewayMetricsFilter

要启用网关指标,请将 spring-boot-starter-actuator 添加为项目依赖项。然后,默认情况下,只要属性 spring.cloud.gateway.metrics.enabled 未设置为 false,网关指标过滤器就会运行。此过滤器添加一个名为 spring.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添加为项目依赖项。

Marking An Exchange As Routed

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

  • ServerWebExchangeUtils.isAlreadyRouted 接受一个 ServerWebExchange 对象并检查它是否已被“路由”。

  • ServerWebExchangeUtils.setAlreadyRouted 接受一个 ServerWebExchange 对象并将其标记为“已路由”。

HttpHeadersFilters

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

ForwardedHeadersFilter

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

RemoveHopByHopHeadersFilter

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

默认删除的headers是:

  • Connection

  • Keep-Alive

  • Proxy-Authenticate

  • Proxy-Authorization

  • TE

  • Trailer

  • Transfer-Encoding

  • Upgrade

要改变这一点,请设置spring.cloud.gateway.filter.remove-hop-by-hop属性设置为要删除的header名称列表。

XForwardedHeadersFilter

XForwarded Headers Filter创建多个X-Forwarded-*头发送给下游服务。它使用当前请求的Host头、 scheme, port和path来创建各种头。

创建单个头信息可以通过以下布尔属性来控制(默认为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 and SSL

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

Example 61. 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 后端,则可以使用以下配置将网关配置为信任所有下游证书:

Example 62. application.yml

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

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

Example 63. application.yml

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

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

TLS Handshake

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

Example 64. application.yml

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

Configuration

Spring Cloud Gateway的配置是由一组RouteDefinitionLocator实例驱动的。下面的清单显示了RouteDefinitionLocator接口的定义:

Example 65. RouteDefinitionLocator.java

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

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

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

Example 66. 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

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

RouteDefinition Metrics

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

Route Metadata Configuration

您可以使用元数据为每条路由配置额外的参数,如下所示:

Example 67. application.yml

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

您可以从一个exchange获取所有元数据属性,如下所示:

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

Http timeouts configuration

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

Global timeouts

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

global http timeouts example

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

Per-route timeouts

要配置每条路由超时: 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();
      }

每个路由的响应超时值为负值将禁用全局响应超时值。

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

Fluent Java Routes API

为了在Java中实现简单的配置,RouteLocatorBuilder bean包含了一个连贯的API。下面的清单显示了它的工作原理:

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

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

The DiscoveryClient Route Definition Locator

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

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

Configuring Predicates and Filters For DiscoveryClient Routes

默认情况下,网关为使用 DiscoveryClient 创建的路由定义单个谓词和过滤器。

默认谓词是path predicate定义的使用模式 /serviceId/** ,其中 serviceId 是来自 DiscoveryClient 的服务的 ID。

默认过滤器是rewrite path filter使用正则表达式 /serviceId/?(?<remaining>.*) 并替换为/${remaining} 。这会在请求被发送到下游之前从路径中去除服务 ID

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

Example 69. application.properties

spring.cloud.gateway.discovery.locator.predicates[0].name: Path
spring.cloud.gateway.discovery.locator.predicates[0].args[pattern]: "'/'+serviceId+'/**'"
spring.cloud.gateway.discovery.locator.predicates[1].name: Host
spring.cloud.gateway.discovery.locator.predicates[1].args[pattern]: "'**.foo.com'"
spring.cloud.gateway.discovery.locator.filters[0].name: CircuitBreaker
spring.cloud.gateway.discovery.locator.filters[0].args[name]: serviceId
spring.cloud.gateway.discovery.locator.filters[1].name: RewritePath
spring.cloud.gateway.discovery.locator.filters[1].args[regexp]: "'/' + serviceId + '/?(?<remaining>.*)'"
spring.cloud.gateway.discovery.locator.filters[1].args[replacement]: "'/${remaining}'"

Reactor Netty Access Logs

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

它必须是Java系统属性,而不是Spring Boot属性。

您可以配置日志记录系统,使其具有单独的访问日志文件。创建Logback配置的示例如下:

Example 70. 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 Configuration

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

Example 71. application.yml

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

在上面的例子中,对于所有GET请求路径,允许来自docs.spring.io的请求使用CORS请求。

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

欢迎关注我的公众号:程序员L札记

更多原创文章,请扫码关注我的微信公众号
更多原创文章,请扫码关注我的微信公众号

分类:

后端

标签:

Java

作者介绍

程序员L札记
V1