Spring Cloud Gateway的核心概念
- Route 路由,它是网关的基础元素,包含ID、目标URI、断言、过滤器组成,当前请求到达网关时,会通过Gateway Handler Mapping,基于断言进行路由匹配,当断言为true时,匹配到路由进行转发
- Predicate,断言,它可以允许开发人员去匹配HTTP请求中的元素,一旦匹配为true,则表示匹配到合适的路由进行转发
- Filter,过滤器,可以在请求发出的前后进行一些业务上的处理,比如授权、埋点、限流等。
它的整体工作原理如下:
其中,predicate就是我们的匹配条件;而filter,就可以理解为一个无所不能的拦截器。有了这两个元素,再加上目标uri,就可以实现一个具体的路由了。
客户端向 Spring Cloud Gateway 发出请求,如果请求与网关程序定义的路由匹配,则该请求就会被发送到网关 Web 处理程序,此时处理程序运行特定的请求过滤器链。
过滤器之间用虚线分开的原因是过滤器可能会在发送代理请求的前后执行逻辑。所有 pre 过滤器逻辑先执行,然后执行代理请求;代理请求完成后,执行 post 过滤器逻辑
Filter
- GlobalFilter
- RouteFilter
AddRequestParameter GatewayFilter Factory
省略第一个路径地址gateway
,AddRequestParameter=param, blue
意思是添加param=blue的参数
spring:
application:
name: spring-cloud-gateway
cloud:
gateway:
routes:
- id: add_request_parameter_route
predicates:
- Path=/gateway/**
uri: http://localhost:8082/
filters:
- StripPrefix=1
- AddRequestParameter=param, blue
RequestRateLimiter GatewayFilter Factory
该过滤器会对访问到当前网关的所有请求执行限流过滤,如果被限流,默认情况下会响应HTTP 429- Too Many Requests。RequestRateLimiterGatewayFilterFactory 默认提供了 RedisRateLimiter 的限流实现,它采用令牌桶算法来实现限流功能
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
@Component
public class IpAddressKeyResolver implements KeyResolver{
@Override
public Mono<String> resolve(ServerWebExchange exchange) {
return Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
}
}
spring:
cloud:
gateway:
routes:
- id: ratelimiter_route
predicates:
- Path=/ratelimiter/**
filters:
- StripPrefix=1
- name: RequestRateLimiter
args:
deny-empty-key: true
keyResolver: '#{@ipAddressKeyResolver}'
redis-rate-limiter.replenishRate: 1
redis-rate-limiter.burstCapacity: 2
uri: lb://order-service
redis-rate-limiter 过滤器有两个配置属性,如果了解令牌桶,就很容易知道它们的含义。
- replenishRate:令牌桶中令牌的填充速度,代表允许每秒执行的请求数。
- burstCapacity:令牌桶的容量,也就是令牌桶最多能够容纳的令牌数。表示每秒用户最大能够执行的请求数量。
Retry GatewayFilter Factory
Retry GatewayFilter Factory 为请求重试过滤器,当后端服务不可用时,网关会根据配置参数来发起重试请求
spring:
cloud:
gateway:
routes:
- id: retry_route
uri: http://www.example.com
predicates:
- Path=/example/**
filters:
- name: Retry
args:
retries: 3
status: 503
- StripPrefix=1
RetryGatewayFilter 提供 4 个参数来控制重试请求,参数说明如下
- retries:请求重试次数,默认值是 3。
- status:HTTP 请求返回的状态码,针对指定状态码进行重试,比如,在上述配置中,当服务端返回的状态码是 503 时,才会发起重试,此处可以配置多个状态码。
- methods:指定 HTTP 请求中哪些方法类型需要进行重试,默认是 GET。
- series:配置错误码段,表示符合某段状态码才发起重试,默认值是 SERVER_ERROR(5),表示5xx 段的状态码都会发起重试。如果 series 配置了错误码段,但是 status 没有配置,则仍然会匹配 series 进行重试。
自定义断言(实现抽象方法AbstractRoutePredicateFactory)
@Component
public class AuthRoutePredicateFactory extends AbstractRoutePredicateFactory<AuthRoutePredicateFactory.Config>{
public AuthRoutePredicateFactory() {
super(Config.class);
}
private static final String NAME_KEY="name";
private static final String VALUE_KEY="value";
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList(NAME_KEY,VALUE_KEY);
}
@Override
public Predicate<ServerWebExchange> apply(Config config) {
//Header中携带了某个值,进行header的判断
return (exchange->{
HttpHeaders headers=exchange.getRequest().getHeaders();
List<String> headerList=headers.get(config.getName());
return headerList.size()>0;
});
}
public static class Config{
private String name;
private String value;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
}
spring:
cloud:
gateway:
routes:
- id: auth_route
predicates:
- Auth=Authorization,token
filters:
- StripPrefix=1
uri: https://www.baidu.com
自定义拦截(实现抽象方法AbstractGatewayFilterFactory)
@Component
public class MyDefineGatewayFilterFactory extends AbstractGatewayFilterFactory<MyDefineGatewayFilterFactory.MyConfig>{
private static final String NAME_KEY="name";
Logger logger= LoggerFactory.getLogger(MyDefineGatewayFilterFactory.class);
public MyDefineGatewayFilterFactory() {
super(MyConfig.class);
}
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList(NAME_KEY);
}
@Override
public GatewayFilter apply(MyConfig config) {
//Filter pre post
return ((exchange,chain)->{
logger.info("[pre] Filter Request, name:"+config.getName());
//TODO
return chain.filter(exchange).then(Mono.fromRunnable(()->{
//TODO
logger.info("[post]: Response Filter");
}));
});
}
public static class MyConfig{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
spring:
cloud:
gateway:
routes:
- id: config_route
predicates:
- Path=/gateway/**
filters:
- StripPrefix=1
- MyDefine=Hello world
uri: http://localhost:8082/
查看gateway的配置
http://ip:port/actuator/gateway/routes