这是我参与11月更文挑战的第23天,活动详情查看:2021最后一次更文挑战。
上篇文章我们实现了动态路由配置和自动更新,这篇文章我们来解读一下SpringCloud Gateway Filter。
解读SpringCloud Gateway Filter(上)
在之前的文章中我们已经有简单介绍过Gateway Filter,它是路由配置的三大组成部分之一,与SpringMVC中的Filter功能和定义是类似的,通过Filter我们可以对请求和响应做出一些修改或者其他自定义的操作。
SpringCloud Gateway Filter的相关概念
1、SpringCloud Gateway 基于过滤器实现,其实是基于过滤器的思想去实现的,与zuul类似,有pre和post两种方式的filter,分别处理前置逻辑(请求进来时) 和后置逻辑(请求返回时)。
2、客户端的请求先经过pre类型的filter,然后将请求转发到具体的业务服务,收到业务服务的响应之后,再经过post类型的filter处理,最后返回响应到客户端。这与SpringMVC中filter的实现思想和效果都是一致的。
3、Filter一共有两大类:全局过滤器和局部过滤器,这两类的工作方式也不相同,全局过滤器它不需要去做额外的声明和配置,它作用于所有请求,而局部过滤器它默认是不起作用的,需要自己去配置。SpringCloud Gateway它自带了很多全局和局部的过滤器。全局过滤器实现了GlobalFilter接口。
解读全局过滤器RouteToRequestUrlFilter
这里解读一下RouteToRequestUrlFilter类,它是全局过滤器的一个。直接看它的filter方法。
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
Route route = (Route)exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
if (route == null) {
return chain.filter(exchange);
} else {
log.trace("RouteToRequestUrlFilter start");
URI uri = exchange.getRequest().getURI();
boolean encoded = ServerWebExchangeUtils.containsEncodedParts(uri);
URI routeUri = route.getUri();
if (hasAnotherScheme(routeUri)) {
exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR, routeUri.getScheme());
routeUri = URI.create(routeUri.getSchemeSpecificPart());
}
if ("lb".equalsIgnoreCase(routeUri.getScheme()) && routeUri.getHost() == null) {
throw new IllegalStateException("Invalid host: " + routeUri.toString());
} else {
URI mergedUrl = UriComponentsBuilder.fromUri(uri).scheme(routeUri.getScheme()).host(routeUri.getHost()).port(routeUri.getPort()).build(encoded).toUri();
exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, mergedUrl);
return chain.filter(exchange);
}
}
}
先从exchange中获取属性GATEWAY_ROUTE_ATTR的值,这是一个route对象,如果值为空就return,否则就继续往下。
RouteToRequestUrlFilter会基于请求的uri以及route对象里面的uri去创建一个新的uri,如果uri的前缀是lb且路由的host是不存在的则抛出异常,因为lb我们需要从注册中心去拿,如果没有host那就没有意义了。(lb就是告诉gateway,我们需要从注册中心里面去找到应用名称叫做xxx的)。
最后就是实现对uri的拼接,创建一个新的uri,包含了scheme,即http和https、host主机名、port端口号去重新build出来。这实际上就是将我们配置的微服务uri地址去转换成我们真实需要的请求路由的uri。新的uri会通过exchange放到属性GATEWAY_REQUEST_URL_ATTR中去继续往下传递。这就完成了这个filter,实现了路由的url的转换过程。
下篇文章会介绍两个局部路由器。