【SpringCloudGateway】SpringCloudGateway路由断言RoutePredicate
一.背景
最近项目中频繁有使用基于SpringCloudGateway组件开发相关功能,如自定义路由断言,自定义拦过滤器,限流,灰度发布等功能,因此通过文章记录开发过程中的细节和问题点,本篇文档主要记录SpringCloudGateway路由断言
二.什么是路由断言
路由断言是由SpringCloudGatway三大基本模块(路由,断言,过滤器)中的路由和断言合并而来,参考官网文档 中对于路由和断言的描述
路由:网关的基本构建块。 它由 ID、目标 URI、断言(谓词)集合和过滤器集合定义。如果聚合断言(谓词)为 true,则匹配路由。
断言(谓词):这是一个Java 8 函数谓词。输入类型是 Spring 框架
ServerWebExchange
。 这使您可以匹配 HTTP 请求中的任何内容,例如标头或参数。 简而言之就是Gateway根据请求特征抽象出来的一系列具有特定功能的拦截器或处理器,仅允许满足映射关系的请求向后执行,即下图中的Gateway Handler Mapping部分
三.断言工厂
SpringCloudGateway内置了多个断言工厂供开发者使用:
The After Route Predicate Factory : 指定日期之后路由断言工厂
The Before Route Predicate Factory:指定日期之前路由断言工厂
The Between Route Predicate Factory:指定日期之间路由断言工厂
The Cookie Route Predicate Factory:Cookie路由断言工厂
The Method Route Predicate Factory:请求方法路由断言工厂
The Path Route Predicate Factory:请求路径路由断言工厂
The Query Route Predicate Factory:查询参数路由断言工厂
The RemoteAddr Route Predicate Factory:请求IP路由断言工厂
The Weight Route Predicate Factory:请求权重路由断言工厂
其中使用的比较多的是Path Route Predicate Factory 例如,
在微服务中常用配置如下
spring:
cloud:
gateway:
routes:
- id: grade_version
uri: lb://nn-version-servant
predicates:
- Path=/speed/gamemaster/gameInfo/version
filters:
- StripPrefix=1
以上配置中 -Path部分即为请求路径断言,表示只有满足该路径的请求才会匹配到当前id为grade_version的路由
注意:断言也可以配置多个,如下
spring:
cloud:
gateway:
routes:
- id: grade_version
uri: lb://nn-version-servant
predicates:
- Path=/speed/gamemaster/gameInfo/version
- RemoteAddr=58.48.225.208
- Header=reqChannel,1
filters:
- StripPrefix=1
以上配置中Path,RemoteAddr,Header三个断言需要同时满足的请求才会匹配到当前路由
四.自定义断言工厂
可以看到 SpringCloudGateway内置的多个断言工厂均继承了 AbstractRoutePredicateFactory,断言工厂名称均以RoutePredicateFactory结尾
我们也可以通过继承该类实现自己的断言工厂NnHeader
@Slf4j public class NnHeaderRoutePredicateFactory extends AbstractRoutePredicateFactory<NnHeaderRoutePredicateFactory.Config> { /** * Header key. */ public static final String NN_HEADER_KEY = "header"; /** * Regexp key. */ public static final String NN_REGEXP_KEY = "regexp"; /** * Allow key */ public static final String NN_ALLOW_KEY = "allow"; public NnHeaderRoutePredicateFactory() { super(Config.class); } @Override public List<String> shortcutFieldOrder() { return Arrays.asList(NN_HEADER_KEY, NN_REGEXP_KEY, NN_ALLOW_KEY); } @Override public Predicate<ServerWebExchange> apply(Config config) { return exchange -> { List<String> values = exchange.getRequest().getHeaders().getOrDefault(config.header, Collections.emptyList()); log.debug("NnHeader匹配规则:{}", JSON.toJSONString(config)); if (values.isEmpty()) { if (config.allow == null) { return false; } return config.allow; } if (config.regexp == null) { return false; } return values.stream() .anyMatch(value -> value.matches(String.valueOf(config.regexp))); }; } @Validated public static class Config { @NotEmpty private String header; private String regexp; private Boolean allow; public String getHeader() { return header; } public Config setHeader(String header) { this.header = header; return this; } public String getRegexp() { return regexp; } public Config setRegexp(String regexp) { this.regexp = regexp; return this; } public Boolean getAllow() { return allow; } public Config setAllow(Boolean allow) { this.allow = allow; return this; } } }
其中Config类三个参数分别是
header:表示请求头的key
value: 表示请求头的value
allow:表示请求头value为空时,是否允许通过
应用到yaml配置中
spring:
cloud:
gateway:
routes:
- id: grade_version
uri: lb://nn-version-servant
predicates:
- Path=/speed/gamemaster/gameInfo/version
- RemoteAddr=58.48.225.208
- NnHeader=reqChannel,1
filters:
- StripPrefix=1
五.问题
1.是否可以配置多个相同的路由断言工厂,例如配置2个Path断言,是否失效? 生效
六.参考
1.SpringCloudGateway官方文档 https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#the-after-route-predicate-factory
2.<<SpringCloudAlibaba微服务原理与实战>>