一、概述
Spring Gateway支持自定义Filter实现,可以实现鉴权、限流、日志记录等功能。其Filter的执行顺序通过Ordered接口定义。Order值越小(可以为负数),则执行顺序越靠前;Oder值越大,则执行顺序越靠后。自定义Filter通过实现GlobalFilter实现。
注意:filter的执行内容分为执行业务代码之前(简称Before),以及执行业务代码之后两个部分(简称After)。Before执行的越靠前,则对应的After执行的顺序越靠后。
二、代码实现
通过一个简单的计时实例先上手。
@Component
public class DurationStatisticsFilter implements GlobalFilter, Ordered {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
logger.info("====== DurationStatisticsFilter start ======");
exchange.getAttributes().put("durationStart", System.currentTimeMillis());
return chain.filter(exchange).doFinally(f -> printDurationTime(exchange));
}
private void printDurationTime(ServerWebExchange exchange) {
long start = exchange.getAttribute("durationStart");
long end = System.currentTimeMillis();
logger.info("====== DurationStatisticsFilter end, cost: {} ======", (end - start));
}
@Override
public int getOrder() {
return WRITE_RESPONSE_FILTER_ORDER - 1;
}
}
通过访问一个API,控制台日志展示如下:
基于此例子,继续拓展下,我们经常需要获取请求的头信息,因此可以打印出请求的所有头信息。
@Component
public class HttpHeaderInfoFilter implements GlobalFilter, Ordered {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
logger.info("====== HttpHeaderInfoFilter start ======");
ServerHttpRequest request = exchange.getRequest();
logger.info("path: {}", request.getPath());
HttpHeaders headers = request.getHeaders();
for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
if (entry.getValue() != null) {
String value = entry.getValue().stream().collect(Collectors.joining(","));
logger.info("entry: {}, value: {}.", entry.getKey(), value);
} else {
logger.info("entry: {}, value is null.", entry.getKey());
}
}
return chain.filter(exchange).doFinally(t -> doFinally(exchange));
}
private void doFinally(ServerWebExchange exchange) {
logger.info("====== HttpHeaderInfoFilter end ======");
}
@Override
public int getOrder() {
return WRITE_RESPONSE_FILTER_ORDER + 1;
}
}
打印的头信息如下:
三、总结
filter的入门级操作还算是比较简单的,实现过程中没有碰到问题,比较顺利。