服务网关:SpringCloud Gateway核心技术
本章概述
SpringCloud Gateway能够实现多种网关功能,比如路由转发、断言、过滤器、熔断、限流、降级、自定义谓词配置、自定义过滤器等等多种功能。今天,我们就一起来聊聊SpringCloud Gateway中的断言、过滤器与熔断机制。
网关断言
断言的英文是Predicate,也可以翻译成谓词。主要的作用就是进行条件判断,可以在网关中实现多种条件判断,只有所有的判断结果都通过时,也就是所有的条件判断都返回true,才会真正的执行路由功能。
SpringCloud Gateway内置断言
SpringCloud Gateway包括许多内置的断言工厂,所有这些断言都与HTTP请求的不同属性匹配。
基于日期时间类型的断言
基于日期时间类型的断言根据时间做判断,主要有三个:
- AfterRoutePredicateFactory:接收一个日期时间参数,判断当前请求的日期时间是否晚于指定的日期时间。
- BeforeRoutePredicateFactory:接收一个日期时间参数,判断当前请求的日期时间是否早于指定的日期时间。
- BetweenRoutePredicateFactory:接收两个日期时间参数,判断当前请求的日期时间是否在指定的时间时间段内。
使用示例
- After=2022-05-10T23:59:59.256+08:00[Asia/Shanghai]
基于远程地址的断言
RemoteAddrRoutePredicateFactory:接收一个IP地址段,判断发出请求的客户端的IP地址是否在指定的IP地址段内。
使用示例
- RemoteAddr=192.168.0.1/24
基于Cookie的断言
CookieRoutePredicateFactory:接收两个参数, Cookie的名称和一个正则表达式。判断请求的Cookie是否具有给定名称且值与正则表达式匹配。
使用示例
- Cookie=name, binghe.
基于Header的断言
HeaderRoutePredicateFactory:接收两个参数,请求Header的名称和正则表达式。判断请求Header中是否具有给定的名称且值与正则表达式匹配。
使用示例
- Header=X-Request-Id, \d+
基于Host的断言
HostRoutePredicateFactory:接收一个参数,这个参数通常是主机名或者域名的模式,例如**.binghe.com这种格式。判断发出请求的主机是否满足匹配规则。
使用示例
- Host=**.binghe.com
基于Method请求方法的断言
MethodRoutePredicateFactory:接收一个参数,判断请求的类型是否跟指定的类型匹配,通常指的是请求方式。例如,POST、GET、PUT等请求方式。
使用示例
- Method=GET
基于Path请求路径的断言
PathRoutePredicateFactory:接收一个参数,判断请求的链接地址是否满足路径规则,通常指的是请求的URI部分。
使用示例
- Path=/binghe/{segment}
基于Query请求参数的断言
QueryRoutePredicateFactory :接收两个参数,请求参数和正则表达式, 判断请求的参数是否具有给定的名称并且参数值是否与正则表达式匹配。
使用示例
- Query=name, binghe.
基于路由权重的断言
WeightRoutePredicateFactory:接收一个[组名,权重]格式的数组,然后对于同一个组内的路由按照权重转发。
使用示例
- id: weight1
uri: http://localhost:8080
predicates:
- Path=/api
@Data
public class NameRoutePredicateConfig implements Serializable {
private static final long serialVersionUID = -3289515863427972825L;
private String name;
}
(2)实现自定义断言时,需要新建类继承org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory类,在io.binghe.shop.predicate包下新建NameRoutePredicateFactory类,继承org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory类,并覆写相关的方法,源码如下所示。
@Component
public class NameRoutePredicateFactory extends AbstractRoutePredicateFactory<NameRoutePredicateConfig> {
public NameRoutePredicateFactory() {
super(NameRoutePredicateConfig.class);
}
@Override
public Predicate<ServerWebExchange> apply(NameRoutePredicateConfig config) {
return (serverWebExchange)->{
String name = serverWebExchange.getRequest().getQueryParams().getFirst("name");
if (StringUtils.isEmpty(name)){
name = "";
}
return name.equals(config.getName());
};
}
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("name");
}
}
(3)在服务网关的application.yml文件中的spring.cloud.gateway.routes节点下的- id: user-gateway下面进行如下配置。
spring:
cloud:
gateway:
routes:
- id: user-gateway
uri: http://localhost:8060
order: 1
predicates:
- Path=/server-user
@Data
public class GrayscaleGatewayFilterConfig implements Serializable {
private static final long serialVersionUID = 983019309000445082L;
private boolean grayscale;
}
(3)在io.binghe.shop.filter包下GrayscaleGatewayFilterFactory类,继承org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory类,主要是实现自定义过滤器,模拟实现灰度发布。代码如下所示。
@Component
public class GrayscaleGatewayFilterFactory extends AbstractGatewayFilterFactory<GrayscaleGatewayFilterConfig> {
public GrayscaleGatewayFilterFactory(){
super(GrayscaleGatewayFilterConfig.class);
}
@Override
public GatewayFilter apply(GrayscaleGatewayFilterConfig config) {
return (exchange, chain) -> {
if (config.isGrayscale()){
System.out.println("开启了灰度发布功能...");
}else{
System.out.println("关闭了灰度发布功能...");
}
return chain.filter(exchange);
};
}
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("grayscale");
}
}
(4)分别启动用户微服务和服务网关,在浏览器中输入http://localhost:10001/server-user/user/get/1001,如下所示。
可以看到,通过服务网关正确访问到了用户微服务,并正确获取到了用户信息。
接下来,查看下服务网关的终端,发现已经成功输出了如下信息。
开启了灰度发布功能...
说明正确实现了自定义的局部过滤器。
全局过滤器
全局过滤器是一系列特殊的过滤器,会根据条件应用到所有路由中。
全局过滤器概述
在SpringCloud Gateway中内置了多种不同的全局过滤器,如下所示。
演示全局过滤器
(1)在服务网关模块shop-gateway模块下的io.binghe.shop.config包下新建GatewayFilterConfig类,并在类中配置几个全局过滤器,如下所示。
@Configuration
@Slf4j
public class GatewayFilterConfig {
@Bean
@Order(-1)
public GlobalFilter globalFilter() {
return (exchange, chain) -> {
log.info("执行前置过滤器逻辑");
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
log.info("执行后置过滤器逻辑");
}));
};
}
}
注意:@Order注解中的数字越小,执行的优先级越高。
(2)启动用户微服务与服务网关,在浏览器中访问http://localhost:10001/server-user/user/get/1001,如下所示。
在服务网关终端输出如下信息。
执行前置过滤器逻辑
执行后置过滤器逻辑
说明我们演示的全局过滤器生效了。
自定义全局过滤器
SpringCloud Gateway内置了很多全局过滤器,一般情况下能够满足实际开发需要,但是对于某些特殊的业务场景,还是需要我们自己实现自定义全局过滤器。
这里,我们就模拟实现一个获取客户端访问信息,并统计访问接口时长的全局过滤器。
(1)在网关服务模块shop-order的io.binghe.shop.filter包下,新建GlobalGatewayLogFilter类,实现org.springframework.cloud.gateway.filter.GlobalFilter接口和org.springframework.core.Ordered接口,代码如下所示。
@Slf4j
@Component
public class GlobalGatewayLogFilter implements GlobalFilter, Ordered {
private static final String BEGIN_VISIT_TIME = "begin_visit_time";
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//先记录下访问接口的开始时间
exchange.getAttributes().put(BEGIN_VISIT_TIME, System.currentTimeMillis());
return chain.filter(exchange).then(Mono.fromRunnable(()->{
Long beginVisitTime = exchange.getAttribute(BEGIN_VISIT_TIME);
if (beginVisitTime != null){
log.info("访问接口主机: " + exchange.getRequest().getURI().getHost());
log.info("访问接口端口: " + exchange.getRequest().getURI().getPort());
log.info("访问接口URL: " + exchange.getRequest().getURI().getPath());
log.info("访问接口URL参数: " + exchange.getRequest().getURI().getRawQuery());
log.info("访问接口时长: " + (System.currentTimeMillis() - beginVisitTime) + "ms");
}
}));
}
@Override
public int getOrder() {
return 0;
}
}
上述代码的实现逻辑还是比较简单的,这里就不再赘述了。
(2)启动用户微服务与网关服务,在浏览器中输入http://localhost:10001/server-user/user/api/filter1?name=binghe,如下所示。
接下来,查看服务网关的终端日志,可以发现已经输出了如下信息。
访问接口主机: localhost
访问接口端口: 10001
访问接口URL: /server-user/user/api/filter1
访问接口URL参数: name=binghe
访问接口时长: 126ms
说明我们自定义的全局过滤器生效了。
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341