目录
- SpringCloud Gateway
- 几个重要概念
- 路由(Route)
- 谓词(Predicate)
- 过滤器(Filter)
- 工作原理
- 配置方式
- 快捷配置
- 完全扩展参数配置
- 路由谓词工厂
- After
- Header
- Host
- Method
- Path
- Query
- RemoteAddr
- Weight
- 过滤器工厂
- Hystrix
- Prefix
- StripPrefix
- RedirectTo
- Retry
- Redis RateLimiter
- 全局过滤器(GlobalFilter)
SpringCloud Gateway
SpringCloud Gateway 是一个基于 Spring 生态系统的 API 网关。基于 Spring Boot 2.x, Spring WebFlux 和 Reactor 构建。因此,使用 Spring Cloud Gateway 时,许多熟悉的同步库(例如,Spring Data 和 Spring Security )和模式可能不适用。
Spring Cloud Gateway 需要Spring Boot 和 Spring Webflux 提供的 Netty 运行时环境。它不能在传统的 Servlet 容器中或作为 WAR 包构建。
几个重要概念
路由(Route)
路由网关的基本模块。它由 ID,目标地址URI,谓词集合和过滤器集合定义。如果聚合谓词为true,则匹配路由。
谓词(Predicate)
Java 8 Function谓词。输入类型为 Spring Framework ServerWebExchange。这使开发人员可以匹配HTTP请求中的任何内容,例如请求头或参数。
过滤器(Filter)
这些是使用特定工厂构造的 Spring Framework GatewayFilter 实例。在此,可以在发送下游请求之前或之后修改请求和响应。
工作原理
客户端向 Spring Cloud Gateway 发出请求。如果网关处理程序映射(Gateway Handler Mapping )确定请求与路由匹配,则将其发送到网关Web处理程序(Gateway Web Handler)。该处理程序通过特定于请求的过滤器链运行请求。过滤器由虚线分隔的原因是,过滤器可以在发送代理请求之前或之后执行逻辑。执行所有“前置”过滤器逻辑,然后发出代理请求。发出代理请求后,将执行“后置”过滤器逻辑。
配置方式
有两种配置谓词和过滤器的方法:快捷配置和完全扩展参数配置。
快捷配置
快捷配置通过过滤器名称标识,后跟等号(=
),再跟由逗号分隔的参数值(,
)。
spring:
cloud:
gateway:
routes:
- id: cookie_route
uri: https://zysite.top
predicates:
- Cookie=mycookie,mycookievalue
上面的示例使用两个参数定义了Cookie
路由谓词工厂,即 cookie 名称与mycookie
匹配以及 cookie 的值与mycookievalue
匹配的请求。
完全扩展参数配置
完全扩展的参数配置看起来更像是 name/value 对的标准Yaml 配置。通常,将有一个name
键和一个args
键。args
键是用于配置谓词或过滤器的键值对的映射。
spring:
cloud:
gateway:
routes:
- id: cookie_route
uri: https://zysite.top
predicates:
- name: Cookie
args:
name: mycookie
regexp: mycookievalue
上面显示的Cookie
谓词的快捷配置的完整配置。regexp
是 Java 正则表达式。
路由谓词工厂
After
After
路由谓词工厂只有一个参数,即datetime
(就是Java ZonedDateTime
)。该谓词匹配在当前日期时间之后发生的请求。
spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://zysite.top
predicates:
- After=2017-01-20T17:42:47.789-07:00[America/Denver]
该路由与2017年1月20日17:42山区时间(丹佛)之后的所有请求匹配。
与之类似的还有Before
,Between
。Between 接收两个 datetime,用逗号隔开。
还有上一部分的示例Cookie
。
Header
Header
路由谓词工厂具有两个参数,请求头name
和regexp
。该谓词与具有给定名称请求头,并且值与正则表达式匹配的请求匹配。
spring:
cloud:
gateway:
routes:
- id: header_route
uri: https://zysite.top
predicates:
- Header=X-Request-Id, \d+
如果请求具有名为X-Request-Id
的请求头,且其值与\d+
正则表达式匹配(具有一个或多个数字的值),则此路由匹配。
Host
Host
路由谓词工厂只有一个参数:主机名patterns
的列表。模式是 Ant 样式的模式,以.
作为分隔符。该谓词匹配请求头中的 Host。
spring:
cloud:
gateway:
routes:
- id: host_route
uri: https://zysite.top
predicates:
- Host=**.spring.io,**.netty.io
上面的路由匹配任意主机以spring.io
、netty.io
结尾发出的请求。如aa.spring.io
、bb.netty.io
。
还支持 URI 模版变量
,如 Host = {sub}.spring.io
,其中sub
即为 URI 模版变量。可通过 ServerWebExchange.getAttributes()
获得 Map,再通过 Map 的 get(“sub”) 获取。
Map<String, String> uriVariables = ServerWebExchangeUtils.getPathPredicateVariables(exchange);
String sub = uriVariables.get("sub");
Method
Method
路由谓词工厂只有一个methods
参数,该参数是一个或多个要匹配的 HTTP 方法。
spring:
cloud:
gateway:
routes:
- id: method_route
uri: https://zysite.top
predicates:
- Method=GET,POST
该路由匹配请求方法为 GET 或 POST 的请求。
Path
Path
路由谓词工厂具有两个参数:Spring PathMatcher
patterns
的列表和matchOptionalTrailingSeparator
的可选标志。
spring:
cloud:
gateway:
routes:
- id: path_route
uri: https://zysite.top
predicates:
- Path=/red/{segment},/blue/{segment}
该路由匹配请求路径以/red
或/blue
开头的请求。如/red/aa
、/blue/bb
。也支持 URI 模版变量。
Query
Query
路由谓词工厂具有两个参数:必需的param
和可选的regexp
。
spring:
cloud:
gateway:
routes:
- id: query_route
uri: https://zysite.top
predicates:
- Query=color,gree.
该路由匹配包含请求参数color
,其值与gree.
正则匹配的请求。
RemoteAddr
RemoteAddr
路由谓词工厂只有一个参数:sources
的列表(最小为 1),它是 CIDR 表示法(IPv4或IPv6)字符串,例如192.168.0.1/16
(其中192.168.0.1
是 IP 地址, 16
是子网掩码)。
spring:
cloud:
gateway:
routes:
- id: remoteaddr_route
uri: https://zysite.top
predicates:
- RemoteAddr=192.168.1.1/24
如果请求的远程地址为192.168.1.10
、192.168.1.100
等,则此路由将匹配。
Weight
Weight
路由谓词工厂具有两个参数group
和weight
(一个int)。权重是按组计算的。
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
此路由会将约80%的流量转发到https://weighthigh.org
并将约20%的流量转发到https://weightlow.org
。
过滤器工厂
路由过滤器允许以某种方式修改传入的 HTTP 请求或传出的 HTTP 响应。路由过滤器适用于特定路由。Spring Cloud Gateway 包括许多内置的 GatewayFilter
工厂。下面示例几个常见的,完整的可以参考 SpringCloud Gateway。
Hystrix
Hystrix 是 Netflix 的一个库,它实现了断路器模式 。Hystrix
过滤器允许您将断路器引入网关路由,保护服务免受级联故障的影响,并允许您在下游故障的情况下提供后备响应(fallback)。
注意:要启用 Hystrix 过滤器,需引入 spring-cloud-starter-netflix-hystrix
的依赖。
Hystrix
过滤器工厂只有一个必选name
参数,它是HystrixCommand
的名称。
spring:
cloud:
gateway:
routes:
- id: hystrix_route
uri: https://zysite.top
filters:
- Hystrix=myCommandName
还可以接受可选的fallbackUri
参数。当前,仅支持forward:
策略的URI。如果调用了 fallback ,则请求将被转发到与URI 相匹配的控制器。
spring:
cloud:
gateway:
routes:
- id: hystrix_route
uri: lb://backing-service:8088
predicates:
- Path=/consumingserviceendpoint
filters:
- name: Hystrix
args:
name: fallbackcmd
fallbackUri: forward:/fallback
- RewritePath=/consumingserviceendpoint, /backingserviceendpoint
当 Hystrix fallback 被调用时,会将请求转发到 Gateway 内部程序的/fallback
URI 上(也可以转发到外部程序的 URI 上)。上述 lb
前缀表示可以整合 Ribbon 的负载均衡。
其实 SpringCloud 还包括 CircuitBreake
过滤器工厂,可以指定断路器模式的实现,如:上面的 Hystrix、Resilience4j 等。另外,还包括FallbackHeaders
过滤器工厂,可以在 fallback 被调用是将一些信息添加到头部后在将请求转发到对应的fallbackUri
。
信息包括:
-
executionExceptionTypeHeaderName
("Execution-Exception-Type"
) -
executionExceptionMessageHeaderName
("Execution-Exception-Message"
) -
rootCauseExceptionTypeHeaderName
("Root-Cause-Exception-Type"
) -
rootCauseExceptionMessageHeaderName
("Root-Cause-Exception-Message"
)
Prefix
PrefixPath
过滤器工厂只有一个prefix
参数。
spring:
cloud:
gateway:
routes:
- id: prefixpath_route
uri: https://zysite.top
filters:
- PrefixPath=/pathprefix
将会把所有请求的路径添加/pathprefix
前缀后转发,如请求 URI 为/hello
将变为/pathprefix/hello
。
StripPrefix
StripPrefix
过滤器工厂只有一个参数parts
。parts
参数指示在向下游发送请求之前,要从请求路径中跳过的地址段数。
spring:
cloud:
gateway:
routes:
- id: nameRoot
uri: https://nameservice
predicates:
- Path=/name/**
filters:
- StripPrefix=2
当请求地址为/name/blue/red
时,发送到nameservice
的地址将变为https://nameservice/red
,即/name/blue
这两段地址被跳过了。
RedirectTo
RedirectTo
过滤器工厂包括一个status
和一个url
参数。状态应该是 300 系列重定向 http 代码,例如301。URL应该是有效的URL 。这将是Location
响应头的值。
spring:
cloud:
gateway:
routes:
- id: redirect_route
uri: https://zysite.top
filters:
- RedirectTo=302, https://spring.io
这将发送状态码为 302 且带有Location:https://spring.io
头部的响应以执行重定向。
Retry
Retry
过滤器工厂支持以下参数:
-
retries
:尝试重试的次数 -
statuses
:应重试的 HTTP 状态码,用org.springframework.http.HttpStatus
表示 -
methods
:应重试的 HTTP 方法,使用org.springframework.http.HttpMethod
表示 -
series
:要重试的一系列状态码,使用org.springframework.http.HttpStatus.Series
表示 -
exceptions
:引发重试的异常列表 -
backoff
:为重试配置了补偿指数。重试在补偿间隔firstBackoff * (factor ^ n)
之后执行,其中n
是迭代。如果配置了maxBackoff
,则应用的最大补偿将被限制为maxBackoff
。如果basedOnPreviousValue
为true,将使用prevBackoff * factor
计算补偿。
spring:
cloud:
gateway:
routes:
- id: retry_test
uri: http://localhost:8080/flakey
predicates:
- Host=*.retry.com
filters:
- name: Retry
args:
retries: 3
statuses: BAD_GATEWAY
methods: GET,POST
backoff:
firstBackoff: 10ms
maxBackoff: 50ms
factor: 2
basedOnPreviousValue: false
Redis RateLimiter
redis 实现基于 Stripe 所做的工作。它需要使用spring-boot-starter-data-redis-reactive
starter 依赖。
使用的算法是令牌桶算法
。
spring:
cloud:
gateway:
routes:
- id: requestratelimiter_route
uri: https://zysite.top
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
redis-rate-limiter.requestedTokens: 1
redis-rate-limiter.replenishRate
是希望用户每秒允许多少个请求,而没有任何丢弃的请求。这是令牌桶被填充的速率。
redis-rate-limiter.burstCapacity
是允许用户在一秒钟内执行的最大请求数。这是令牌桶可以容纳的令牌数。
redis-rate-limiter.requestedTokens
是一个请求耗费的 token 数量,默认为1。
通过在replenishRate
和burstCapacity
中设置相同的值可以达到稳定的速率。通过将burstCapacity
设置为高于replenishRate
,可以允许临时突发。
速率限制器也可以定义为实现RateLimiter
接口的bean。在配置中,使用SpEL通过名称引用bean。#{@myRateLimiter}
是一个SpEL表达式,引用名称为myRateLimiter
的bean。
spring:
cloud:
gateway:
routes:
- id: requestratelimiter_route
uri: https://zysite.top
filters:
- name: RequestRateLimiter
args:
rate-limiter: "#{@myRateLimiter}"
key-resolver: "#{@userKeyResolver}"
还有很多过滤器工厂没有提到,像 添加请求头/响应头,添加/删除请求参数,删除响应头,重写请求路径,修改响应体等等。官方文档有详细解释。
全局过滤器(GlobalFilter)
GlobalFilter
接口具有与GatewayFilter
类似的含义,只不过GatewayFilter
只针对匹配了特定路由的请求进行处理,而GlobalFilter
则对所有请求都进行处理。
当一个请求到达 Gateway,网关Web处理程序(Gateway Web Handler)将会把GlobalFilter
和匹配的GatewayFilter
组成一个过滤器链(根据优先级,即 Order 接口返回的值,越小优先级越高,可以为负值)。
一个简单的全局过滤器实现如下:
@Component
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;
}
}
SpringCloud 还有一些内置的全局过滤器,如:LoadBalancerClientFilter
、NettyRoutingFilter
等等。可在官网或者源码org.springframework.cloud.gateway.filter
包中查看。