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

18 KiB
Raw Blame History

spring cloud gateway

项目引入spring cloud gateway

如果要在项目中引入spring cloud gateway可以在项目pom文件中添加如下依赖

<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配置方式

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匹配发生在指定时间之后的请求。

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匹配发生在某时间之前的请求。

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示例

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接收两个参数nameregexp。该predicate匹配请求中含有指定名称并且cookie值满足regexp正则表达式。如下展示了一个cookie predicate示例

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接收两个参数headerregexpregexp是正则表达式。该predicate会匹配一个拥有指定名称header的请求且header对应的值要满足regexp表达式。
如下示例显示了header route predicate的用法

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会匹配Hostheader示例如下所示

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示例

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

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使用。
可以通过如下的工具类方法来对这些变量进行访问,按如下示例所示:

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

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

Query Route Predicate Factory

Query Route Predicate Factory接收两个参数必填参数param和可选参数regexp示例如下所示

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

上述路由配置匹配请求参数中含有green参数的请求

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示例

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-Forheader进行解析该resolver是XForwardedRemoteAddressResolver
XForwardedRemoteAddressResolver有两个静态的构造器方法分别使用了两种不同的安全方式

  • XForwardedRemoteAddressResolver::trustAll返回一个RemoteAddressResolver会一直从X-Forwarded-For中取第一个ip address。该方法很容易收到欺骗因为恶意客户端程序会设置X-Forwarded-For字段的初始值而此时reslover会接收虚假设置的值。
  • XForwardedRemoteAddressResolver::maxTrustedIndex接收一个index该index和Spring Cloud Gateway之前运行的受信任设施的数量相关。

如存在如下header

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代码来完成相同的配置

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接收两个参数groupweightweight将对每个group进行计算。如下示例配置了一个Weight Route Predicate

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地址列表时请求才会被允许访问。

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

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

上述配置对所有匹配的请求在下游请求头中添加了X-Request-red:blueheader。
AddRequestHeader可以使用用于匹配path或host的URI变量。URI变量可以在value中使用并且在运行时自动拓展如下示例配置了一个使用URI变量的AddRequestHeader GatewayFilter

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

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

上述配置会添加两个headersX-Request-Color-1:blueX-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

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

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

上述配置会向下游请求中加入请求参数。
AddRequestParameter GatewayFilter可以使用URI变量使用URI变量的配置如下所示

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

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变量的配置

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

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

CacheRequestBody GatewayFilter Factory

有一些场景需要读取请求体因为请求只能被读取一次因此需要缓存请求体。可以使用CacheRequestBody filter来缓存请求体在请求被发送到下游之前并且可以从exchange属性中获取请求体。

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示例

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

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

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