Spring Cloud / Alibaba 微服务架构 | 2021年11月更文挑战(25)

101 阅读3分钟

这是我参与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的转换过程。

下篇文章会介绍两个局部路由器。