美文网首页
SpringCloud系列之网关gateway-8.过滤器原理和

SpringCloud系列之网关gateway-8.过滤器原理和

作者: 那钱有着落吗 | 来源:发表于2021-09-15 09:28 被阅读0次

过滤器的工作模式

所有开源框架实现过滤器的模式都是大同小异,通过一种类似职责链的方式,传统的职责链模式中的事件会传递直到有一个处理对象接手,而过滤器和传统的职责链有点不同,它更像是足球队开场握手一样,所有队员一字排开,你要从头到尾依次和所有球员握过手。

Gateway中的过滤器也是一样的模型,他们经过优先级的排列,所有网关调用请求从最高优先级的过滤器开始,一路走到头,直到被最后一个过滤器处理。

过滤器的实现方式

在Gateway中实现一个过滤器非常简单,只要实现GatewayFilter接口的默认方法就好了

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 随意发挥
return chain.filter(exchange);
}

这里面有两个关键信息:

  • ServerWebExchange 这是Spring封装的HTTP request-response交互协议,从中我们可以获取request和response中的各种请求参数,也可以向其中添加内容
  • GatewayFilterChain 它是过滤器的调用链,在方法结束的时候我们需要将exchange对象传入调用链中的下一个对象

过滤器的执行阶段

不同于Spring Cloud中上一代网关组件Zuul里对过滤器的Pre和Post的定义,Gateway是通过Filter中的代码来实现类似Pre和Post的效果。
Pre和Post是指代当前过滤器的执行阶段,Pre是在下一个过滤器之前被执行,Post是在过滤器执行过后再执行。我们在Gateway Filter中也可以同时定义Pre和Post执行逻辑。

Pre类型

我们就拿AddResponseHeaderGatewayFilterFactory举例,它可以向Response中添加Header信息:

@Override
public GatewayFilter apply(NameValueConfig config) {
  return (exchange, chain) -> {
          exchange.getResponse().getHeaders().add(config.getName(), config.getValue());
    return chain.filter(exchange);
  };
}

这里的具体执行方法是定义在调用“chain.filter()”方法之前,也就是在转发到下级调用链路之前执行的,因此可以理解为一个Pre类型的过滤器。

Post类型

我们拿SetStatusGatewayFilterFactory举例,它在过滤器执行完毕之后,将制定的HTTP status返回给调用方。

return chain.filter(exchange).then(Mono.fromRunnable(() -> {
    // 这里是业务逻辑
}));

这个过滤器的主要逻辑在then方法中,then是一个回调函数,在下级调用链路都完成以后再执行,因此这类过滤器可以看做是Post Filter。

过滤器排座次

在Gateway中我们可以通过实现org.springframework.core.Ordered接口,来给过滤器指定执行顺序,比如下面的代码实现了Ordered接口方法,将过滤器执行顺序设置为0:

@Override
public int getOrder() {
  return 0;
}

Pre类型的过滤器来说,数字越大表示优先级越高,也就越早被执行。但对于Post类型的过滤器,则是数字越小越先被执行。

注意:过滤器基本都在org.springframework.cloud.gateway.filter.factory包里

Header过滤器

这个系列有很多组过滤器,AddRequestHeader和AddResponseHeader,分别向Request和Response里加入指定Header。相应的RemoveRequestHeader和RemoveResponseHeader分别做移除操作,用法也很简单:

.filters(f -> f.addResponseHeader("who", "gateway-header"))

上面的例子会向header中添加一个who的属性,对应的值是gateway-header。

StripPrefix过滤器

这是个比较常用的过滤器,它的作用是去掉部分URL路径。比如我们的过滤器配置如下:

.route(r -> r.path("/gateway-test/**")
.filters(f -> f.stripPrefix(1))
.uri("lb://FEIGN-SERVICE-PROVIDER/")
)

假如HTTP请求访问的是
/gateway-test/sample/update
,如果没有StripPrefix过滤器,那么转发到FEIGN-SERVICE-PROVIDER服务的访问路径也是一样的。当我们添加了这个过滤器之后,Gateway就会根据“stripPrefix(1)”中的值截取URL中的路径,比如这里我们设置的是1,那么就去掉一个前缀,最终发送给后台服务的路径变成了“/sample/update”

PrefixPath过滤器

它和StripPrefix的作用是完全相反的,会在请求路径的前面加入前缀

.route(r -> r.path("/gateway-test/**")
.filters(f -> f.prefixPath("go"))
.uri("lb://FEIGN-SERVICE-PROVIDER/")
)

比如说我们访问“/gateway-test/sample”的时候,上面例子中配置的过滤器就会把请求发送到“/go/gateway-test/sample”。

RedirectTo过滤器

它可以把收到特定状态码的请求重定向到一个指定网址:

.filters(f -> f.redirect(404, "https://www.imooc.com/"))

上面的例子接收HTTP status code和URL两个参数,如果请求结果是404,则重定向到第二个参数指定的页面,这个功能也可以做统一异常处理,将Unauthorized或Forbidden请求重定向到登录页面。

SaveSession过滤器

我们知道微服务是无状态的会话,所以大多都不依赖session机制,但是如果你有分布式session的需求,比如说某些功能是基于spring-session和spring-security来实现的,那么这个过滤器或许对你有用,它在调用服务之前都会强制保存session

.filters(f -> f.saveSession())

相关文章

网友评论

      本文标题:SpringCloud系列之网关gateway-8.过滤器原理和

      本文链接:https://www.haomeiwen.com/subject/stqcgltx.html