Spring Cloud Gateway(译)(Part 1)

Spring Cloud Gateway

2.2.2.RELEASE

该项目提供了一个在Spring生态系统之上构建的API网关,包括:Spring 5,Spring Boot 2和Project Reactor。 Spring Cloud Gateway旨在提供一种简单而有效的方法来路由到API,并为它们提供跨领域的关注点,例如:安全性,监视/指标和弹性。

1.如何在项目中引入Spring Cloud Gateway

要想在项目中引入Spring Cloud Gateway,你需要引入一个starter, group ID 为 org.springframework.cloud 并且 artifact ID 为: spring-cloud-starter-gateway . 如下所示:


    org.springframework.cloud
    spring-cloud-starter-gateway

如果已经引入了starter,但不希望启用网关,请设置 spring.cloud.gateway.enabled = false。

Spring Cloud Gateway基于Spring Boot 2.x,Spring WebFlux和Project Reactor构建。 结果是,当您使用Spring Cloud Gateway时,许多您熟悉的同步库(例如,Spring Data和Spring Security)和模式可能不适用。 如果您不熟悉这些项目,建议您在使用Spring Cloud Gateway之前先阅读它们的文档以熟悉一些新概念。

Spring Cloud Gateway需要Netty运行时是由Spring Boot和Spring Webflux提供的。 它不能在传统的Servlet容器中或构建成WAR使用。

2.词汇表

  • Route: 网关的基本构建块。 它由ID,目标URI,predicates集合和filters集合组成。 如果aggregate predicates为true,则匹配路由。

  • Predicate: 这就是 Java 8 Function Predicate. 传入的参数类型是 Spring Framework ServerWebExchange. 可以匹配HTTP请求中的所有内容,例如 headers 或 parameters 。

  • Filter: 这些是使用特定工厂构造的 Spring Framework GatewayFilter 实例。所以,你可以在发送下游请求之前或之后修改请求和响应。

3. 它是怎么工作的

下图从总体上概述了Spring Cloud Gateway的工作方式:

spring_cloud_gateway_diagram.png

客户端向Spring Cloud Gateway发出请求。 Gateway Handler Mapping 判断请求与路由是否匹配,若匹配,则将其发送到 Gateway Web Handler. 该handler通过该request的filter链来运行请求。 filters由虚线分隔的原因是, filters可以在发送代理请求之前和之后运行逻辑。 所有“pre” filter逻辑均被执行。 然后发出代理请求。 发出代理请求后,将运行“post” filter逻辑。

若路由中定义的URIs没有给定端口号,那么HTTP和HTTPS URI的默认端口值分别为80和443。

4.配置Route Predicate工厂和Gateway Filter 工厂

有两种配置predicates 和 filters 的方法:简洁配置和完全扩展的参数。 下面的大多数示例都使用简洁配置。

名称和参数名称将在每个部分的第一个或两个句子中以代码形式列出。 参数通常按简洁配置所需的顺序列出。

4.1简洁配置

简洁配置由过滤器名称识别,后跟一个等号(=),然后是由逗号分隔参数值(,)。

application.yml

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

上一个示例定义了Cookie Route Predicate Factory 包含了两个参数,这两个参数是cookie名称【mycookie】和与之匹配的值【mycookievalue】。

4.2 完全扩展的参数

完全扩展的参数看起来更像带有 name/value 键值对的标准Yaml配置. 通常, 将有一个name 键 和一个 args 键. args 键是用于配置 predicate 或 filter的键值对映射(map).

application.yml

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

这是上面显示的Cookie predicate 的简洁配置的完整配置。

5. Route Predicate 工厂

Spring Cloud Gateway将路由匹配作为Spring WebFlux HandlerMapping基础架构的一部分。 Spring Cloud Gateway包括许多内置的Route Predicate工厂。 所有这些predicates 都与HTTP请求的不同属性匹配。 您可以将多个Route Predicate工厂组合使用。

5.1. The After Route Predicate Factory

这个After route predicate factory 包括一个参数, 即 datetime (这是一个java的 ZonedDateTime). 这个predicate 匹配发生在特定时间之后的请求 . 下面是一个 after route predicate的配置示例:

Example 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]

这个route 匹配任何发生在 20, 2017 17:42 Mountain Time (Denver) 之后的请求.

5.2. The Before Route Predicate Factory

这个Before route predicate factory 包括一个参数, 即 datetime (这是一个java的 ZonedDateTime). 这个predicate 匹配发生在特定datetime 之前的请求. 下面是一个 before route predicate 的配置示例:

Example 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]

这个route 匹配任何发生在 Jan 20, 2017 17:42 Mountain Time (Denver)之前的请求.

5.3. The Between Route Predicate Factory

Between route predicate factory 有连个参数, datetime1datetime2 它们是 java ZonedDateTime 对象. 这个predicate 匹配发生在 datetime1datetime2之间的请求. 而且datetime2 参数必须在 datetime1之后. 下面是一个 between route predicate 的配置示例:

Example 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]

这个route 匹配 Jan 20, 2017 17:42 Mountain Time (Denver) 之后而且 Jan 21, 2017 17:42 Mountain Time (Denver)之前的请求. 这对于维护时段可能很有用.

5.4. The Cookie Route Predicate Factory

The Cookie route predicate factory 有两个参数, 即cookie nameregexp (这是一个java正则表达式). 这个predicate 匹配 有给定的名称的 cookies 并且其值符合正在表达式. 下面是cookie route predicate factory的配置示例:

Example 4. application.yml

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

这个route 匹配拥有名称为chocolate 并且值匹配 ch.p 正则表达式.

5.5. The Header Route Predicate Factory

这个Header route predicate factory 包含两个参数, header nameregexp (java正则表达式). 这个predicate 匹配给定名称的 header 并且值匹配 正则表达式. 下面是 header route predicate的配置示例:

Example 5. application.yml

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

如果请求有一个名为 X-Request-Id 的header 并且值匹配 \d+ 正则表达式(其值为一个或多个数字),则此路由匹配

5.6. The Host Route Predicate Factory

Host route predicate factory 拥有一个参数: host name patterns集合. 该模式是一种Ant样式模式使用 . 作为分隔符 . predicates 匹配 Host header 作为匹配模式. 下面是host route predicate的配置示例:

Example 6. application.yml

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

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

如果请求的 Host 头为 www.somehost.orgbeta.somehost.orgwww.anotherhost.org, 则该模式匹配.

该predicate 提取URI模板变量(如上例中定义的 sub) 作为名称和值的映射. 并使用ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE 中定义的key 将其存储在ServerWebExchange.getAttributes() 中 . 这些值会在 GatewayFilter factories 中使用.

5.7. The Method Route Predicate Factory

Method Route Predicate Factory 拥有一个名为methods 的参数,该参数是一个集合,包含一个或多个HTTP 方法(GETHEADPOSTPUTDELETECONNECTOPTIONSTRACEPATCH). 下面是 method route predicate 配置示例:

Example 7. application.yml

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

该route 匹配请求方法是 GETPOST.

5.8. The Path Route Predicate Factory

Path Route Predicate Factory 携带两个参数: 一个 Spring PathMatcher patterns 列表和一ge个名为matchOptionalTrailingSeparator可选标志. 下面是path route predicate的配置示例:

Example 8. application.yml

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

该 route 匹配以下请求路径, 如: /red/1 or /red/blue or /blue/green.

该predicate 提取URI模板变量(如上例中定义的 segment) 作为名称和值的映射. 并使用ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE 中定义的key 将其存储在ServerWebExchange.getAttributes() 中 . 这些值会在 GatewayFilter factories 中使用.

可以使用程序的方法 (叫get) 来简化对这些变量的访问. 下面的示例演示如何使用 get 方法:

Map uriVariables = ServerWebExchangeUtils.getPathPredicateVariables(exchange);

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

5.9. The Query Route Predicate Factory

Query route predicate factory 有两个参数: 必选参数param 和可选参数 regexp (这是一个java正则表达式). 下面是query route predicate配置示例:

Example 9. application.yml

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

如果请求中包含green 查询参数,则该路由匹配.

application.yml

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

该preceding route matches 匹配请求中包含 red 的查询参数并且其值匹配 gree. 正则表达式, 所以 greengreet 都匹配

5.10. The RemoteAddr Route Predicate Factory

RemoteAddr route predicate factory 包含一个源列表(只有一个值)参数, 这些源是CIDR标记(IPv4或IPv6)字符串,例如 192.168.0.1/16 (其中192.168.0.1 是 IP 地址,而16 是子网掩码). 下面示例是RemoteAddr route predicate 的配置示例:

Example 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,则此路由匹配.

5.11. The Weight Route Predicate Factory

Weight route predicate factory 携带两个参数: groupweight (int类型). 权重是按组计算的. 下面是 weight route predicate 的配置示例:

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

该route 会将大约80% 的流量转发到 weighthigh.org, 大约20%的流量转发到 weighlow.org

5.11.1. Modifying the Way Remote Addresses Are Resolved

默认情况下,RemoteAddr route predicate factory使用传入请求中的远程地址。 如果Spring Cloud Gateway位于代理层之后,则可能与实际的客户端IP地址不匹配。

你可以通过实现 RemoteAddressResolver来自定义解析远程地址的方式. Spring Cloud Gateway 内置了一个非default的名为XForwardedRemoteAddressResolver解析器,它是基于 X-Forwarded-For header 请求头的。

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

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

例如以下标头值:

X-Forwarded-For: 0.0.0.1, 0.0.0.2, 0.0.0.3

下面不同maxTrustedIndex 值产生不同的远程地址:

maxTrustedIndex result
[Integer.MIN_VALUE,0] (invalid, IllegalArgumentException during initialization)
1 0.0.0.3
2 0.0.0.2
3 0.0.0.1
[4, Integer.MAX_VALUE] 0.0.0.1

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

Example 12. 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")
)

你可能感兴趣的:(Spring Cloud Gateway(译)(Part 1))