前篇对predicate断言进行了介绍,对于前端发送的请求,先通过网关的predicate断言找到对应路由处理,在路由处理之前,需要经过前置过滤器处理,处理返回响应之后,可以由后置过滤器处理,然后转发到相应服务。
与zuul不同的是,filter除了分为“pre前置”和“post后置”两种方式的filter外,在Spring Cloud Gateway中,filter从作用范围可分为另外两种,一种是针对于单个路由的gateway filter,它在配置文件中的写法同predict类似;另外一种是针对于所有路由的global gateway filer。
由filter工作流程点,可以知道filter有着非常重要的作用,在“pre”类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等,在“post”类型的过滤器中可以做响应内容、响应头的修改,日志的输出,流量监控等。
在微服务的上一层加一个全局的权限控制、限流、日志输出的Api Gatewat服务,然后再将请求转发到具体的业务服务层。这个Api Gateway服务就是起到一个服务边界的作用,外接的请求访问系统,必须先通过网关层。
Spring Cloud Gateway 的 Filter 的生命周期有两个:“pre” 和 “post”。“pre”和 “post” 分别会在请求被执行前调用和被执行后调用
Spring Cloud Gateway已经给我们提供了许多已经定义好的过滤器
这里介绍常用的几个,如果想更多了解可以到提供的Jar包内学习
1.AddRequestHeader GatewayFilter Factory
在请求头添加信息
routes:
- id: add_request_header_route
uri: http://httpbin.org:80/get
filters: - AddRequestHeader=X-Request-Foo, Bar
2.RewritePath GatewayFilter Factory
改变请求路径
filters:
# 访问localhost:8080/test, 请求会转发到localhost:8001/app/test
- RewritePath=/test, /app/test
url: localhost:8001
3.StripPrefixGatewayFilter Factory
进行请求路径截断
filters:
# 访问localhost:8080/test/user, 请求会转发到localhost:8001/user
- StripPrefix=1 #去除请求第一个级前缀
url: localhost:8001
4.PrefixPath GatewayFilter Factory
PrefixPath Filter 的作用和 StripPrefix 正相反,是在 URL 路径前面添加一部分的前缀
spring:
cloud:
gateway:
routes:
- id: prefixpath_route
uri: http://example.org
filters:
- PrefixPath=/mypath
以上简单介绍了几种常见的过滤器使用配置,如果想自定义过滤器使用,怎么做?
跟据内置的那些过滤器,他们都是继承AbstractGatewayFilterFactory抽象类并重写apply方法。
以此自定义过滤器需要2步
第一步:
创建一个以GatewayFilterFactory结尾的类继承AbstractGatewayFilterFactory抽象类,并重写里面的apply方法
第二步:
注入到Spring Ioc容器里
第三步:
配置文件(这里需要注意的就是名称,举个例子)
比如:我自定义了DenfineGatewayFilterFactory类
这里的配置就是
filters:
- Denfine=false(值跟据场景,可以随意设置,配置名称DenfineGatewayFilterFactory必须为Denfine)
这里写一个案例,在某个路由下具备打印日志,统计该请求的耗时时间
@Component
public class DenfineGatewayFilterFactory extends AbstractGatewayFilterFactory<DenfineGatewayFilterFactory.Config> {
Logger logger=LoggerFactory.getLogger(DenfineGatewayFilterFactory.class);
private static final String NAME_KEY="name";
public DenfineGatewayFilterFactory() {
super(Config.class);
}
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
exchange.getAttributes().put("attrbute_time", System.currentTimeMillis());
return chain.filter(exchange).then(
Mono.fromRunnable(() -> {
Long startTime = exchange.getAttribute("attrbute_time");
if (startTime != null) {
StringBuilder sb = new StringBuilder(exchange.getRequest().getURI().getRawPath())
.append("---此接口耗时")
.append(": ")
.append(System.currentTimeMillis() - startTime)
.append("ms");
logger.info(sb.toString());
}
})
);
};
}
public List<String> shortcutFieldOrder() {
return Arrays.asList(NAME_KEY);
}
public static class Config{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
server:
port: 8082
spring:
cloud:
gateway:
routes: #路由配置
- id: auto-office-user
uri: http://localhost:8084
predicates: #谓词匹配
- Path=/test/user/** #匹配路径
filters:
- StripPrefix=1 #去除第一个级前缀
- Denfine=false
Spring Cloud Gateway与zuul不同的地方,Gateway可以跟据作用范围分为局部和全局的过滤器。局部过滤器前面已经介绍,下面对全局的过滤器进行介绍。
这里比较好理解直接上代码了
1.实现接口 GlobalFilter, Ordered
public class GlobelFilterTest implements GlobalFilter, Ordered {
Logger logger= LoggerFactory.getLogger(GlobelFilterTest.class);
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
exchange.getAttributes().put("start_time", System.currentTimeMillis());
return chain.filter(exchange).then(
Mono.fromRunnable(() -> {
Long startTime = exchange.getAttribute("start_time");
if (startTime != null) {
StringBuilder sb = new StringBuilder("全局拦截---")
.append(exchange.getRequest().getURI().getRawPath())
.append("---接口耗时")
.append(": ")
.append(System.currentTimeMillis() - startTime)
.append("ms");
logger.info(sb.toString());
}
})
);
}
@Override
public int getOrder() {
return 0;
}
}
在上面的代码中,Ordered中的int getOrder()方法是来给过滤器设定优先级别的,值越大则优先级越低。
2.注入到spring容器
@Configuration
public class FilterConfig {
@Bean
public GlobelFilterTest globelFilterTest(){
return new GlobelFilterTest();
}
// @Bean
// public DenfineGatewayFilterFactory denfineGatewayFilterFactory(){
// return new DenfineGatewayFilterFactory();
// }
}