Files
rikako-note/spring/Spring Cloud/Spring Cloud gateway.md

445 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# spring cloud gateway
## 项目引入spring cloud gateway
如果要在项目中引入spring cloud gateway可以在项目pom文件中添加如下依赖
```xml
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
```
> 如果已经在项目中引入了spring-cloud-starter-gateway的依赖但是不想启用gateway可以在配置文件中指定`spring.cloud.gateway.enabled=false`
> Spring Cloud gateway在运行时需要netty作为运行时环境并且采用Spring Webflux构建gateway在传统的基于servlet的环境中无法运行。
## Spring Cloud gateway核心概念
- Routegateway的基本构建单元Route由一个id、一个目标uripredicate集合、filter集合组成。如果聚合predicate为true那么route被匹配到
- PredicatePredicate的输入是` Spring Framework ServerWebExchange`通过该输入可以匹配http请求中的任何内容如header或请求参数等
- Filter其是GatewayFilter的实例通过特定的factory构造。在filter中可以在发送到下游请求之前或者之后对request和response进行修改。
## Spring Cloud Gateway如何工作
1. 客户端向spring cloud gateway发送请求如果Gateway Handler Mapping将请求匹配到route那么会向gateway web handler发送请求
2. gateway web handler通过filter chain对请求进行处理
## 配置route predicate factories和gateway filter factories
有两种方式来配置predicate和filtershortcuts和全展开参数
### shortcut配置方式
```yml
spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://example.org
predicates:
- Cookie=mycookie,mycookievalue
```
## Route Predicate Factories
Spring Cloud Gateway包含了许多内置的route predicate factories所有的这些predicate都匹配到http请求的不同属性。可以通过逻辑运算符`and`将多个route predicate factory组合起来。
### After Route Predicate Factory
After Route Predicate Factory接收一个参数`datetime`该参数为ZonedDateTime类型该Predicate匹配发生在指定时间之后的请求。
```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匹配2017-01-20T17:42:47.789-07:00[America/Denver]该时间之后的任意请求
### Before Route Predicate Factory
Before route predicate factory接收一个`datetime`参数参数为ZonedDateTime类型该predicate匹配发生在某时间之前的请求。
```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匹配发生在2017-01-20T17:42:47.789-07:00[America/Denver]之前的任意请求
### Between Route Predicate Factory
Between Route Predicate Factory接收两个参数都是ZonedDateTime类型该predicate匹配发生在datetime1和datetime2之间的请求其中第二个参数指定的时间必须位于第一个参数指定时间之后。如下指定了一个between predicate示例
```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]
```
### Cookie Route Predicate Factory
Cookie Route Predicate Factory接收两个参数`name``regexp`。该predicate匹配请求中含有指定名称并且cookie值满足`regexp`正则表达式。如下展示了一个cookie predicate示例
```xml
spring:
cloud:
gateway:
routes:
- id: cookie_route
uri: https://example.org
predicates:
- Cookie=chocolate, ch.p
```
上述cookie_route会匹配请求中含有name为chocolate的cookie并且cookie值满足`ch.p`正则表达式的请求。
### Header Route Predicate Factory
Header Route Predicate Factory接收两个参数`header``regexp`regexp是正则表达式。该predicate会匹配一个拥有指定名称header的请求且header对应的值要满足regexp表达式。
如下示例显示了header route predicate的用法
```yml
spring:
cloud:
gateway:
routes:
- id: header_route
uri: https://example.org
predicates:
- Header=X-Request-Id, \d+
```
### Host Route Predicate Factory
Host Route Predicate Factory接收一个参数一个pattern列表。pattern是ant-style并用`.`作为分隔符。该predicate会匹配`Host`header示例如下所示
```yml
spring:
cloud:
gateway:
routes:
- id: host_route
uri: https://example.org
predicates:
- Host=**.somehost.org,**.anotherhost.org
```
URI template 变量例如`{sub}.myhost.org`也支持。
该route会匹配如下请求headers中包含name为Host的header并且Host header的值为`www.somehost.org`,`beta.somehost.org`,`www.anotherhost.org`等形式
### Method Route Predicate Factory
Method Route Predicate Factory接收一个`methods`参数其指定了匹配的HTTP METHOD. 如下示例指定了一个method route predicate示例
```yml
spring:
cloud:
gateway:
routes:
- id: method_route
uri: https://example.org
predicates:
- Method=GET,POST
```
该predicate匹配method为GET或POST的任意请求。
### Path Route Predicate Factory
Path Route Predicate Factory接收两个参数一个PathMatcher Pattern的列表和一个可选的matchTrailingSlash默认设置为true
如下实例配置了一条path route predicate
```yml
spring:
cloud:
gateway:
routes:
- id: path_route
uri: https://example.org
predicates:
- Path=/red/{segment},/blue/{segment}
```
上述配置的route能够匹配/red/1或/red/1/、/red/blue或/blue/green.
如果`matchTrailingSlash`被设置为false那么/red/1/将不会被匹配到。
该predicate将URI template变量例如segment解析为name、value键值对并且放到ServerWebExchange.getAttributes()中。这些值可以被GatewayFilter factories使用。
可以通过如下的工具类方法来对这些变量进行访问,按如下示例所示:
```java
Map<String, String> uriVariables = ServerWebExchangeUtils.getUriTemplateVariables(exchange);
String segment = uriVariables.get("segment");
```
### Query Route Predicate Factory
Query Route Predicate Factory接收两个参数必填参数param和可选参数regexp示例如下所示
```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.
```
该route则是匹配请求参数含有red并且其value满足`gree.`正则表达式的请求。
### RemoteAddr Route Predicate Factory
RemoteAddr route predicate factory接收一个`sources`列表列表最小长度为1列表元素为ipv4或ipv6字符串例如`192.168.0.1/1`.
如下显示了一个RemoteAddr route predicate示例
```yml
spring:
cloud:
gateway:
routes:
- id: remoteaddr_route
uri: https://example.org
predicates:
- RemoteAddr=192.168.1.1/24
```
该route匹配如下请求如果请求的remote addr满足表达式例如`192.168.1.10`
#### 修改Remote Addr的解析方式
默认情况下RemoteAddr predicate factory的解析方式是使用请求的remote address。但是如果Spring Cloud Gateway如果位于proxy layer之后那么remote address匹配的不是实际的client ip。
可以通过自定义`RemoteAddressResolver`来自定义remote address的解析方式。Spring Cloud Gateway附带了一个非默认的remote address reslover该reslover基于` X-Forwarded-For`header进行解析该resolver是`XForwardedRemoteAddressResolver`
XForwardedRemoteAddressResolver有两个静态的构造器方法分别使用了两种不同的安全方式
- `XForwardedRemoteAddressResolver::trustAll`返回一个RemoteAddressResolver会一直从`X-Forwarded-For`中取第一个ip address。该方法很容易收到欺骗因为恶意客户端程序会设置`X-Forwarded-For`字段的初始值而此时reslover会接收虚假设置的值。
- `XForwardedRemoteAddressResolver::maxTrustedIndex`接收一个index该index和Spring Cloud Gateway之前运行的受信任设施的数量相关。
如存在如下header
```yml
X-Forwarded-For: 0.0.0.1, 0.0.0.2, 0.0.0.3
```
如下maxTrustedIndex会产生的remote address将如下所示
| maxTrustedIndex | result |
| :-: | :-: |
| [Integer.MIN_VALUE,0] | 该范围输入不合法 |
| 1 | 0.0.0.3 |
| 2 | 0.0.0.2 |
| 3 | 0.0.0.1 |
| [4, Integer.MAX_VALUE] | 0.0.0.1 |
如下展示了如何通过java代码来完成相同的配置
```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 Route Predicate Factory
Weight Route Predicate Factory接收两个参数`group``weight`weight将对每个group进行计算。如下示例配置了一个Weight Route Predicate
```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%的负载转发到https://weighthigh.org把20%的负载发送到https://weightlow.org
### XForwarded Remote Addr Route Predicate
XForwarded Remote Addr Route Predicate接收一个`sources`列表列表元素为ipv4或ipv6地址例如`192.168.0.1/16`
该route predicate允许通过`X-Forwarded-For` header来过滤请求。
该predicate可以和反向代理服务器通常用作负载均衡或web应用防火墙一起使用只有当请求来源于这些受信ip地址列表时请求才会被允许访问。
```yml
spring:
cloud:
gateway:
routes:
- id: xforwarded_remoteaddr_route
uri: https://example.org
predicates:
- XForwardedRemoteAddr=192.168.1.1/24
```
上述route只有当`X-Forwarded-For` header中包含例如`192.168.1.10`的ip时请求才会被匹配。
## GatewayFilter Factory
Route filters 允许对进入的请求和外出的响应进行修改Route Filter作用域为特定的route。Spring Cloud Gateway有许多内置的route filter。
### AddRequestHeader GatewayFilter Factory
AddRequestHeader GatewayFilter Factory接收一个name和value参数如下示例配置了一个AddRequestHeader GatewayFilter
```yml
spring:
cloud:
gateway:
routes:
- id: add_request_header_route
uri: https://example.org
filters:
- AddRequestHeader=X-Request-red, blue
```
上述配置对所有匹配的请求在下游请求头中添加了`X-Request-red:blue`header。
AddRequestHeader可以使用用于匹配path或host的URI变量。URI变量可以在value中使用并且在运行时自动拓展如下示例配置了一个使用URI变量的`AddRequestHeader GatewayFilter`
```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}
```
### AddRequestHeadersIfNotPresent GatewayFilter Factory
AddRequestHeadersIfNotPresent GatewayFilter接收一个name和value对集合name和value之间通过`:`进行分隔如下示例配置了一个filter
```yml
spring:
cloud:
gateway:
routes:
- id: add_request_headers_route
uri: https://example.org
filters:
- AddRequestHeadersIfNotPresent=X-Request-Color-1:blue,X-Request-Color-2:green
```
上述配置会添加两个headers`X-Request-Color-1:blue``X-Request-Color-2:green`到下游请求的headers中。该操作和`AddRequestHeader`类似但是AddRequestHeadersIfNotPresent只会当header不存在时才进行添加。如果该header存在那么会保留该header的原有值。
> 如果要设置一个multi-valued header可以使用该headerName多次例如`AddRequestHeadersIfNotPresent=X-Request-Color-1:blue,X-Request-Color-1:green`
`AddRequestHeadersIfNotPresent`也支持URI变量如下配置了一个使用URI变量的Gateway Filter
```yml
spring:
cloud:
gateway:
routes:
- id: add_request_header_route
uri: https://example.org
predicates:
- Path=/red/{segment}
filters:
- AddRequestHeadersIfNotPresent=X-Request-Red:Blue-{segment}
```
### AddRequestParameter GatewayFilter Factory
AddRequestParameter GatewayFilter Factory接收一个name和value参数如下示例配置了一个filter
```xml
spring:
cloud:
gateway:
routes:
- id: add_request_parameter_route
uri: https://example.org
filters:
- AddRequestParameter=red, blue
```
上述配置会向下游请求中加入请求参数。
AddRequestParameter GatewayFilter可以使用URI变量使用URI变量的配置如下所示
```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 GatewayFilter Factory
`AddResponseHeader GatewayFilter Factory接收一个name和value参数如下配置了一个filter
```yml
spring:
cloud:
gateway:
routes:
- id: add_response_header_route
uri: https://example.org
filters:
- AddResponseHeader=X-Response-Red, Blue
```
该filter添加了`X-Response-Red:Blue` header到下游响应的headers中。
`AddResponseHeader GatewayFilter`可以使用URI变量如下实例展示了使用URI变量的配置
```yml
spring:
cloud:
gateway:
routes:
- id: add_response_header_route
uri: https://example.org
predicates:
- Host: {segment}.myhost.org
filters:
- AddResponseHeader=foo, bar-{segment}
```
### CircuitBreaker GatewayFilter Factory
CircuitBreaker GatewayFilter Factory使用了Spring Cloud CircuitBreaker API来将网关路由包装到断路器中。
为了启用Spring Cloud CircuitBreaker filter需要将`spring-cloud-starter-circuitbreaker-reactor-resilience4j`放到classpath路径下如下示例配置了filter
```xml
spring:
cloud:
gateway:
routes:
- id: circuitbreaker_route
uri: https://example.org
filters:
- CircuitBreaker=myCircuitBreaker
```
### CacheRequestBody GatewayFilter Factory
有一些场景需要读取请求体因为请求只能被读取一次因此需要缓存请求体。可以使用CacheRequestBody filter来缓存请求体在请求被发送到下游之前并且可以从`exchange`属性中获取请求体。
```xml
spring:
cloud:
gateway:
routes:
- id: cache_request_body_route
uri: lb://downstream
predicates:
- Path=/downstream/**
filters:
- name: CacheRequestBody
args:
bodyClass: java.lang.String
```
上述配置获取请求体并且将请求体转为了String类型后续可以通过`ServerWebExchange.getAttributes()`来获取key为`ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR`.
### DedupeResponseHeader GatewayFilter Factory
DedupeResponseHeader GatewayFilter factory接收一个name参数和一个可选的strategy参数name是一个用空格分隔的listlist元素为header name。如下配置了一个filter示例
```yml
spring:
cloud:
gateway:
routes:
- id: dedupe_response_header_route
uri: https://example.org
filters:
- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
```
上述配置中移除了Access-Control-Allow-Credentials和Access-Control-Allow-Origin响应header中的重复值当gateway cors逻辑和下游逻辑都添加了它们时。
DedupeResponseHeader还有一个可选的strategy参数默认为RETAIN_FIRST还可以是RETAIN_LAST和RETAIN_UNIQUE。
### 默认filters
如果想要添加一个filter并将其应用到所有的routes中可以使用`spring.cloud.gateway.default-filters`该属性可以接收一个filter列表。如下定义了一系列默认filter
```yml
spring:
cloud:
gateway:
default-filters:
- AddResponseHeader=X-Response-Default-Red, Default-Blue
- PrefixPath=/httpbin
```
## Global Filters
GlobalFilter接口的签名和Gateway接口的签名一样。GlobalFilter会在满足条件后应用于所有的routes。
### 组合Global Filter和Gateway Filter
当请求匹配到一个route之后filtering web handler将所有的GlobalFilter实例和route对应的Gateway Filter实例添加到一个filter chain中。该filter chain通过`org.springframework.core.Ordered`接口进行排序。filter chain中排序最靠前的filter在pre-phase中位于第一个并且在post-phase中位于最后一个。
如下配置了一个filter chain
```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;
}
}
```