Spring Cloud / Alibaba 微服务架构

这是我参与11月更文挑战的第24天,活动详情查看:2021最后一次更文挑战

上篇文章我们介绍了SpringCloud Gateway Filter的相关概念,并解读了一个全局过滤器——RouteToRequestUrlFilter的filter方法,这篇文章我们来介绍一下两个局部过滤器。

解读SpringCloud Gateway Filter(下)

全局过滤器是实现GlobalFilter, Ordered接口,局部过滤器是实现GatewayFilter, Ordered接口,然后再去实现对应的apply方法。

1、添加前缀的局部过滤器 PrefixPathGatewayFilterFacotry

可以看出来,这是一个局部过滤器的工厂,在工厂内实现了一个局部过滤器。有一个属性 PREFIX_KEY,是指明需要在url上增加的前缀。

接下来看下代码实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
scss复制代码public GatewayFilter apply(PrefixPathGatewayFilterFactory.Config config) {
return new GatewayFilter() {
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
boolean alreadyPrefixed = (Boolean)exchange.getAttributeOrDefault(ServerWebExchangeUtils.GATEWAY_ALREADY_PREFIXED_ATTR, false);
if (alreadyPrefixed) {
return chain.filter(exchange);
} else {
exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_ALREADY_PREFIXED_ATTR, true);
ServerHttpRequest req = exchange.getRequest();
ServerWebExchangeUtils.addOriginalRequestUrl(exchange, req.getURI());
String newPath = config.prefix + req.getURI().getRawPath();
ServerHttpRequest request = req.mutate().path(newPath).build();
exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, request.getURI());
if (PrefixPathGatewayFilterFactory.log.isTraceEnabled()) {
PrefixPathGatewayFilterFactory.log.trace("Prefixed URI with: " + config.prefix + " -> " + request.getURI());
}

return chain.filter(exchange.mutate().request(request).build());
}
}

public String toString() {
return GatewayToStringStyler.filterToStringCreator(PrefixPathGatewayFilterFactory.this).append("prefix", config.getPrefix()).toString();
}
};
}

alreadyPrefixed是boolean类型,用来校验一下是否已经添加前缀了,通过exchange.getAttributeOrDefault中的GATEWAY_ALREADY_PREFIXED_ATTR属性来判断,默认值为false。

接下来使用config的Prefix去构造新的路径,新的HttpRequest。先根据exchange.getRequest()获取请求对应的request,然后根据request获取到对应的url,然后在url上去添加一个前缀生成新的path,用这个新的path去构造新的ServerHttpRequest。

举个例子,假如有个简单的静态路由配置如下:

1
2
3
4
5
6
7
yaml复制代码spring:
cloud:
routes:
-id: sheep
uri: http//example/org
filters:
- PrefixPath=/mypath

假如现在有个请求/hello,命中了上方的配置,那么这个添加前缀的局部过滤器就会将这个请求变成:http://example/org/mypath/hello。

2、去除前缀的局部过滤器 StripPrefixGatewayFilterFactory

strip是跳过的意思,所以该过滤器是用来去掉前缀的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
scss复制代码public GatewayFilter apply(StripPrefixGatewayFilterFactory.Config config) {
return new GatewayFilter() {
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
ServerWebExchangeUtils.addOriginalRequestUrl(exchange, request.getURI());
String path = request.getURI().getRawPath();
String newPath = "/" + (String) Arrays.stream(StringUtils.tokenizeToStringArray(path, "/")).skip((long)config.parts).collect(Collectors.joining("/"));
newPath = newPath + (newPath.length() > 1 && path.endsWith("/") ? "/" : "");
ServerHttpRequest newRequest = request.mutate().path(newPath).build();
exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, newRequest.getURI());
return chain.filter(exchange.mutate().request(newRequest).build());
}

public String toString() {
return GatewayToStringStyler.filterToStringCreator(StripPrefixGatewayFilterFactory.this).append("parts", config.getParts()).toString();
}
};
}

通过request.getURI().getRawPath()去获取原始的URI,然后根据配置的parts部分去执行.skip(config.parts)去掉前缀。parts是int类型,也就是指定一个数字,去掉几个前缀的部分。

然后将获取到的新path去构造一个新的request再进行转发。

举个例子,假如有个简单的静态路由配置如下:

1
2
3
4
5
6
7
8
9
yaml复制代码spring:
cloud:
routes:
-id: sheep
uri: http//example/org
predicates:
- Path=/name/**
filters:
- StripPrefix=2

如果这时候有个请求是/name/bar/foo命中了上方的配置,那么这个请求就会变成/foo,要注意的是,这个stripPrefix=2指的是去掉两个”/xxx”,而不是字符!

SpringCloud Gateway Filter 的执行流程

1、过滤器有优先级之分,Order越大,优先级就越低,越晚被执行。可以通过getOrder方法获取Order。

2、全局过滤器所有的请求都会执行,这是默认的行为,不需要做额外的操作,针对自定义的全局过滤器也是如此。

3、局部过滤器只有配置的请求才会执行,配置在路由配置中,之后文章会介绍如何配置才会使其生效。

自定义局部过滤器的步骤

1、自定义局部过滤器实现GatewayFilter, Ordered 这两个接口中的相应方法。

2、将自定义的局部过滤器加入到过滤器工厂中,并将工厂加入到Spring IOC容器中,工厂继承 AbstractGatewayFilterFactory 抽象类。

3、配置文件中配置过滤器,使其生效。

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%