4-服务网关Gateway_自定义过滤器学习笔记(2020.3.31)
前言:
Spring Cloud Gateway 已经内置了很多实用的过滤器,但并不能完全满足我们的需求。本文我们就来实现自定义过滤器。
用于常见的过滤请求, token验证, 请求参数验证什么的。
1.Filter 的生命周期
Spring Cloud Gateway 的 Filter 的生命周期不像 Zuul 的那么丰富,它只有两个:“pre” 和 “post”。
“pre” 和 “post” 分别会在请求被执行前调用和被执行后调用,和 Zuul Filter 或 Spring Interceptor 中相关生命周期类似,但在形式上有些不一样。
Zuul 的 Filter 是通过
filterType()
方法来指定,一个 Filter 只能对应一种类型,要么是 “pre” 要么是 “post”。Spring Interceptor 是通过重写HandlerInterceptor
中的三个方法来实现的。而 Spring Cloud Gateway 基于 Project Reactor 和 WebFlux,采用响应式编程风格,打开它的 Filter 的接口GatewayFilter
你会发现它只有一个方法filter
。下面我们就来实现一下自定义过滤器, 对请求头的token进行认证。
自定义过滤器需要实现
GatewayFilter
和Ordered
。其中GatewayFilter
中的这个方法就是用来实现你的自定义的逻辑的
Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
而
Ordered
中的int getOrder()
方法是来给过滤器设定优先级别的,值越大则优先级越低。
1.1 自定义普通过滤器
/**
* 此过滤器功能为计算请求完成时间
*/
public class MyFilter implements GatewayFilter, Ordered {
private static final String ELAPSED_TIME_BEGIN = "elapsedTimeBegin";
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
exchange.getAttributes().put(ELAPSED_TIME_BEGIN, System.currentTimeMillis());
return chain.filter(exchange).then(
Mono.fromRunnable(() -> {
Long startTime = exchange.getAttribute(ELAPSED_TIME_BEGIN);
if (startTime != null) {
System.out.println(exchange.getRequest().getURI().getRawPath() + ": " + (System.currentTimeMillis() - startTime) + "ms");
}
})
);
}
/*
*过滤器存在优先级,order越大,优先级越低
*/
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
}
定义好
MyFilter
以后,其需要跟Route
绑定使用,不能在application.yml
文件中配置使用
@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder) {
return builder.routes().route(r ->
r.path("/abc/**")
//去掉前缀1节
.filters(p->p.stripPrefix(1))
//转发路由
.uri("lb://eureka-client")
//注册自定义过滤器
.filters(new MyFilter())
//给定id
.id("user-service")
).build();
}
1.2 自定义全局过滤器
自定义过滤器, 假设对请求头的token进行认证。
/**
* @Author: zhihao
* @Date: 2020/3/31 17:38
* @Description: 自定义过滤器
* @Versions 1.0
**/
@Component //交给框架管理
public class MyGatewayFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//1.获取请求对象
ServerHttpRequest request = exchange.getRequest();
//2.获取请求头Authenticate
List<String> authenticate = request.getHeaders().get("Authenticate");
if (null == authenticate || authenticate.isEmpty()) {
//说明Authenticate为空,返回错误码,阻止通过网关路由
ServerHttpResponse response = exchange.getResponse();
Map<String,String> resultMap = new LinkedHashMap<>();
resultMap.put("code", "401");
resultMap.put("message", "没有token");
String jsonStr = JSONUtil.toJsonStr(resultMap);
//将错误信息输出页面
DataBuffer dataBuffer = response.bufferFactory().wrap(jsonStr.getBytes());
response.setStatusCode(HttpStatus.UNAUTHORIZED); //状态码
response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
Mono<Void> mono = response.writeWith(Mono.just(dataBuffer));
return mono;
//return response.setComplete();
}
//......可以通过
String[] strings = authenticate.toArray(new String[authenticate.size()]);
String str = strings[0];
return chain.filter(exchange);
}
@Override
public int getOrder() {
//值越大则优先级越低。
return -1;
}
}
er(exchange);
}
@Override
public int getOrder() {
//值越大则优先级越低。
return -1;
}
}
1