Gateway 网关 (二) 全局过滤器
废话可以先看看某大佬对Gateway过滤器的理解:GateWay过滤器 - 天宇轩-王 - 博客园网关就像是一个电影院的门口,所有观众进场都需要从这个门口进去,大点的影院可能有多个门口(集群),所以一些验票操作、识别操作、统计操作等都需要在门口这里完成,并且还要高效,不然所有人都拥挤在门口,或者是进门1小时观影1分钟,那就得出事故了。除了验票之外,还要给工作人员(资源文件)这类无需验票的人员放行。
废话
可以先看看某大佬对Gateway过滤器的理解:GateWay过滤器 - 天宇轩-王 - 博客园
网关就像是一个电影院的门口,所有观众进场都需要从这个门口进去,大点的影院可能有多个门口(集群),所以一些验票操作、识别操作、统计操作等都需要在门口这里完成,并且还要高效,不然所有人都拥挤在门口,或者是进门1小时观影1分钟,那就得出事故了。除了验票之外,还要给工作人员(资源文件)这类无需验票的人员放行。
所以权限校验这里,能用在内存层面完成的就在内存解决,内存解决不了的就换缓存,缓存还解决不了的才去数据库寻求支持,数据库都解决不了的,杀个程序员祭天吧。
概述
Gateway过滤器主要分两种,GatewayFilter局部过滤器、GlobalFilter全局过滤器。
这里主要实现2个逻辑:
(1)LogFilter,用于记录输入输出日志
(2)AuthFilter,用于校验请求是否合法、用户权限校验等(不怕麻烦的话,用户权限校验可以再封装一个过滤器)
GlobalFilter主要就是两个方法,filter和getOrder,filter就是过滤逻辑执行的地方了,order则表示过滤器的等级,数值越低等级越优先。所以我们将LogFilter的等级设置为-1为最高级别,记录所有的请求和响应信息,AuthFilter则设置10。
需要注意的是LogFilter这里,因为是需要等接口处理完成之后,才能把返回的日志拉出来记录,这个东西相比纯过滤器,耗费的资源应该要多很多,如果有其他更好的办法记录日志的话,就尽量不要在这里记录了。
代码
配置啥的就省略了,详情参考上一个文章。
具体逻辑跟注意事项我都写代码里了,直接看吧:
@Slf4j
@Component//这个不能漏啊,不然扫描不到这里就会导致过滤器不生效
public class LogFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpResponse originalResponse = exchange.getResponse();
DataBufferFactory bufferFactory = originalResponse.bufferFactory();
ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
@Override
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
if (body instanceof Flux) {
//这里需要注意,如果是在本过滤器或者是其他过滤器中,过滤规则不通过然后直接返回错误信息的话,是到不了这一步的,这点切记。
//这个问题目前我没找到解决方案,所以建议其他过滤器那边,认证不通过的时候,另外也记录一份日志。
Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
return super.writeWith(fluxBody.buffer().map(dataBuffer -> {
//从缓存中把返回的数据提取出来
DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
DataBuffer join = dataBufferFactory.join(dataBuffer);
byte[] content = new byte[join.readableByteCount()];
join.read(content);
//释放掉内存
DataBufferUtils.release(join);
String s = new String(content, StandardCharsets.UTF_8);
//记录输入输出
log.info("type:api;param:{};cookie:{};hear:{};url:{};value:{}",
exchange.getRequest().getQueryParams().toString(), exchange.getRequest().getCookies().toString(),
exchange.getRequest().getHeaders().toString(), exchange.getRequest().getURI().toString(),
s);
//返回的结果已经提取出来打日志了,所以需要将数据重新写入
byte[] uppedContent = new String(s.getBytes(), StandardCharsets.UTF_8).getBytes();
return bufferFactory.wrap(uppedContent);
}));
}
return super.writeWith(body);
}
};
//继续执行
return chain.filter(exchange.mutate().response(decoratedResponse).build());
}
@Override
public int getOrder() {
return -1;
}
}
@Slf4j
@Component
public class AuthFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//权限验证逻辑,忽略,这里直接返回验证不通过
if (true) {
ServerHttpResponse response = exchange.getResponse();
DataBuffer buffer = response.bufferFactory().wrap("非法登录".getBytes(StandardCharsets.UTF_8));
response.setStatusCode(HttpStatus.UNAUTHORIZED);
response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
return response.writeWith(Mono.just(buffer));
}
//认证通过,往下走
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 10;
}
}
更多推荐
所有评论(0)