GatewayFilter是网关中提供的过滤器,对请求进行各种处理,然后响应给客户端。
一、过滤器知识点
1. 生命周期
Spring Cloud Gateway 的 Filter 生命周期很简单,它只有:pre 和 post 。
- PRE: 这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
- POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的 HTTPHeader、收集统计信息和指标、将响应从微服务发送给客户端等。
2. 过滤器类型
Spring Cloud Gateway 的 Filter 从作用范围上课分为两种:GatewayFilter 和 GlobalFilter。
局部过滤器(GatewayFilter)
局部过滤器(GatewayFilter)是针对单个路由的过滤器,对访问的URL过滤,切面处理。在Spring Cloud Gateway中通过GatewayFilter的形式内置了很多不同类型的局部过滤器。
全局过滤器(GlobalFilter)
全局过滤器(GlobalFilter)作用于所有的路由,可以通过自定义实现自己的 GlobalFilter。通过全局过滤器实现对所有请求的的统一校验。
二、实战
以上篇 springboot集成Gateway & Nacos「再来一刀」 搭建的测试环境开发。
1. 局部过滤
局部过滤含有26个GatewayFilter Factory,下面用 AddRequestHeader 和 AddResponseHeader 举栗子。
AddRequestHeader :通过配置name和value可以增加请求的header。 AddResponseHeader:通过配置name和value可以增加请求的参数。
其它的 Factory 的使用,可以参考其它作者的文章
二当家的黑板报:spring cloud gateway系列教程2——GatewayFilter_上篇
(1)application.yml 配置
spring:
cloud:
gateway:
discovery:
locator:
enabled: true
lower-case-service-id: true
routes:
- id: springboot-gateway-client-a
uri: lb://springboot-gateway-client-a
predicates:
- Path=/sgca/**
filters:
- AddRequestHeader=X-Request-Token, 2020ABC
- AddResponseHeader=X-Response-Token, 2020ABC
(2)测试接口
@RequestMapping(value = "/2")
public String test2(@RequestHeader(value = "X-Request-Token", required = false) String token){
return "req token:"+token;
}
2. 全局过滤
自定义全局过滤器是平时开发中最常用的,用于对所有请求的安全校验。
实现拦截器,需要继承两个类:GlobalFilter, Ordered。
GlobalFilter:全局过滤拦截器。 Orderer:拦截器的顺序,数值越小,执行的优先级越高。
(1)提取Request内容
ServerHttpRequest request = exchange.getRequest();
String path = request.getPath().pathWithinApplication().value();
String scheme = request.getURI().getScheme();
HttpMethod method = request.getMethod();
HttpHeaders httpHeaders = request.getHeaders();
InetSocketAddress remoteAddress = request.getRemoteAddress();
//不建议提取body数据,因为请求体数据只能被消费一次。
logger.info("\npath:{}\nscheme:{}\nmethod:{}\nheaders:{}\nremoteAddress:{}",
path,scheme,method,httpHeaders,remoteAddress);
(2)header增加token
ServerHttpRequest newRequest = exchange.getRequest().mutate().headers(headers -> {
headers.add("X-Gatewaw-Token","2022ABC");
headers.add("X-Gatewaw-Token","2022ABC");
}).build();
(3)计算请求时长
exchange.getAttributes().put("START_TIME", System.currentTimeMillis());
return chain.filter(exchange.mutate().request(newRequest).build()).then( Mono.fromRunnable(() -> {
Long startTime = exchange.getAttribute("START_TIME");
if (startTime != null) {
Long executeTime = (System.currentTimeMillis() - startTime);
logger.info(exchange.getRequest().getURI().getRawPath() + " : " + executeTime + "ms");
}
}));
三、开发避免的坑
平时开发过程是,尽量避免提取request body数据,因为请求体数据只能被消费一次。
解决方案:SpringCloud Gateway 内部提供了一个断言工厂类ReadBodyPredicateFactory,这个类实现了读取Request的Body内容并放入缓存,我们可以通过从缓存中获取body内容来实现我们的目的。
具体的如何使用,还没尝试,后续更新吧。
springboot集成Gateway DEMO:gitee.com/renxiaoshi/…