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发出请求。 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 有连个参数, datetime1
和datetime2
它们是 java ZonedDateTime
对象. 这个predicate 匹配发生在 datetime1
和 datetime2
之间的请求. 而且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 name
和 regexp
(这是一个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 name
和 regexp
(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.org
或 beta.somehost.org
或 www.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 方法(GET
,HEAD
,POST
,PUT
,DELETE
,CONNECT
,OPTIONS
,TRACE
,PATCH
). 下面是 method route predicate 配置示例:
Example 7. application.yml
spring:
cloud:
gateway:
routes:
- id: method_route
uri: https://example.org
predicates:
- Method=GET,POST
该route 匹配请求方法是 GET
或 POST
.
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.
正则表达式, 所以 green
和 greet
都匹配
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 携带两个参数: group
和weight
(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")
)