详解SpringCloud Gateway之过滤器GatewayFilter

在Spring-Cloud-Gateway之请求处理流程文中我们了解最终网关是将请求交给过滤器链表进行处理,接下来我们阅读Spring-Cloud-Gateway的整个过滤器类结构以及主要功能

通过源码可以看到Spring-Cloud-Gateway的filter包中吉接口有如下三个,GatewayFilter,GlobalFilter,GatewayFilterChain,下来我依次阅读接口的主要实现功能。

GatewayFilterChain

类图

代码

/**
 * 网关过滤链表接口
 * 用于过滤器的链式调用
 * Contract to allow a {@link WebFilter} to delegate to the next in the chain.
 *
 * @author Rossen Stoyanchev
 * @since 5.0
 */
public interface GatewayFilterChain {

  /**
   * 链表启动调用入口方法
   * Delegate to the next {@code WebFilter} in the chain.
   * @param exchange the current server exchange
   * @return {@code Mono<Void>} to indicate when request handling is complete
   */
  Mono<Void> filter(ServerWebExchange exchange);

}
  /**
   * 网关过滤的链表,用于过滤器的链式调用
   * 过滤器链表接口的默认实现,
   * 包含2个构建函数:
   * 1.集合参数构建用于初始化吧构建链表
   * 2. index,parent参数用于构建当前执行过滤对应的下次执行的链表
   */
  private static class DefaultGatewayFilterChain implements GatewayFilterChain {

    /**
     * 当前过滤执行过滤器在集合中索引
     */
    private final int index;
    /**
     * 过滤器集合
     */
    private final List<GatewayFilter> filters;

    public DefaultGatewayFilterChain(List<GatewayFilter> filters) {
      this.filters = filters;
      this.index = 0;
    }

    /**
     * 构建
     * @param parent 上一个执行过滤器对应的FilterChain
     * @param index 当前要执行过滤器的索引
     */
    private DefaultGatewayFilterChain(DefaultGatewayFilterChain parent, int index) {
      this.filters = parent.getFilters();
      this.index = index;
    }

    public List<GatewayFilter> getFilters() {
      return filters;
    }

    /**
     * @param exchange the current server exchange
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange) {
      return Mono.defer(() -> {
        if (this.index < filters.size()) {
          //获取当前索引的过滤器
          GatewayFilter filter = filters.get(this.index);
          //构建当前索引的下一个过滤器的FilterChain
          DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(this, this.index + 1);
          //调用过滤器的filter方法执行过滤器
          return filter.filter(exchange, chain);
        } else {
          //当前索引大于等于过滤集合大小,标识所有链表都已执行完毕,返回空
          return Mono.empty(); // complete
        }
      });
    }
  }

过滤器的GatewayFilterChain 执行顺序

  1. 通过GatewayFilter集合构建顶层的GatewayFilterChain
  2. 调用顶层GatewayFilterChain,获取第一个Filter,并创建下一个Filter索引对应的GatewayFilterChain
  3. 调用filter的filter方法执行当前filter,并将下次要执行的filter对应GatewayFilterChain传入。

GatewayFilter

类图

/**
 * 网关路由过滤器,
 * Contract for interception-style, chained processing of Web requests that may
 * be used to implement cross-cutting, application-agnostic requirements such
 * as security, timeouts, and others. Specific to a Gateway
 *
 * Copied from WebFilter
 *
 * @author Rossen Stoyanchev
 * @since 5.0
 */
public interface GatewayFilter extends ShortcutConfigurable {

  String NAME_KEY = "name";
  String VALUE_KEY = "value";

  /**
   * 过滤器执行方法
   * Process the Web request and (optionally) delegate to the next
   * {@code WebFilter} through the given {@link GatewayFilterChain}.
   * @param exchange the current server exchange
   * @param chain provides a way to delegate to the next filter
   * @return {@code Mono<Void>} to indicate when request processing is complete
   */
  Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);

}

网关过滤器接口,有且只有一个方法filter,执行当前过滤器,并在此方法中决定过滤器链表是否继续往下执行,接下来我们看下几个主要的功能实现类

OrderedGatewayFilter

/**
 * 排序的网关路由过滤器,用于包装真实的网关过滤器,已达到过滤器可排序
 * @author Spencer Gibb
 */
public class OrderedGatewayFilter implements GatewayFilter, Ordered {

  //目标过滤器
  private final GatewayFilter delegate;
  //排序字段
  private final int order;

  public OrderedGatewayFilter(GatewayFilter delegate, int order) {
    this.delegate = delegate;
    this.order = order;
  }

  @Override
  public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    return this.delegate.filter(exchange, chain);
  }
}

OrderedGatewayFilter实现类主要目的是为了将目标过滤器包装成可排序的对象类型。是目标过滤器的包装类

GatewayFilterAdapter

  /**
   * 全局过滤器的包装类,将全局路由包装成统一的网关过滤器
   */
  private static class GatewayFilterAdapter implements GatewayFilter {

    /**
     * 全局过滤器
     */
    private final GlobalFilter delegate;

    public GatewayFilterAdapter(GlobalFilter delegate) {
      this.delegate = delegate;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
      return this.delegate.filter(exchange, chain);
    }
  }

GatewayFilterAdapter实现类主要目的是为了将GlobalFilter过滤器包装成GatewayFilter类型的对应。是GlobalFilter过滤器的包装类

GlobalFilter

GlobalFilter 为请求业务以及路由的URI转换为真实业务服务的请求地址的核心过滤器,不需要配置,模式系统初始化时加载,并作用在每个路由上。

初始化加载,通过GatewayAutoConfiguration自动创建

GatewayAutoConfiguration 类

    /**
     * 全局过滤器,用户通过HttpClient转发请求
     * @param httpClient
     * @param headersFilters
     * @return
     */
    @Bean
    public NettyRoutingFilter routingFilter(HttpClient httpClient,
                        ObjectProvider<List<HttpHeadersFilter>> headersFilters) {
      return new NettyRoutingFilter(httpClient, headersFilters);
    }

    /**
     * 全局的过滤器,用户将HttpClient客户端转发请求的响应写入到原始的请求响应中
     * @param properties
     * @return
     */
    @Bean
    public NettyWriteResponseFilter nettyWriteResponseFilter(GatewayProperties properties) {
      return new NettyWriteResponseFilter(properties.getStreamingMediaTypes());
    }

GatewayLoadBalancerClientAutoConfiguration 类

  /**
   * 全局过滤器,用于在通过负载均衡客户端选择服务实例信息
   * @param client
   * @return
   */
  @Bean
  @ConditionalOnBean(LoadBalancerClient.class)
  public LoadBalancerClientFilter loadBalancerClientFilter(LoadBalancerClient client) {
    return new LoadBalancerClientFilter(client);
  }

GlobalFilter转换成GatewayFilter,并作用于每个路由上,在FilteringWebHandler实现

FilteringWebHandler类

  /**
   * 包装加载全局的过滤器,将全局过滤器包装成GatewayFilter
   * @param filters
   * @return
   */
  private static List<GatewayFilter> loadFilters(List<GlobalFilter> filters) {
    return filters.stream()
        .map(filter -> {
          //将所有的全局过滤器包装成网关过滤器
          GatewayFilterAdapter gatewayFilter = new GatewayFilterAdapter(filter);
          //判断全局过滤器是否实现了可排序接口
          if (filter instanceof Ordered) {
            int order = ((Ordered) filter).getOrder();
            //包装成可排序的网关过滤器
            return new OrderedGatewayFilter(gatewayFilter, order);
          }
          return gatewayFilter;
        }).collect(Collectors.toList());
  }
  @Override
  public Mono<Void> handle(ServerWebExchange exchange) {
    //获取请求上下文设置的路由实例
    Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
    //获取路由定义下的网关过滤器集合
    List<GatewayFilter> gatewayFilters = route.getFilters();

    //组合全局的过滤器与路由配置的过滤器
    List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
    //添加路由配置过滤器到集合尾部
    combined.addAll(gatewayFilters);
    //对过滤器进行排序
    //TODO: needed or cached?
    AnnotationAwareOrderComparator.sort(combined);

    logger.debug("Sorted gatewayFilterFactories: "+ combined);
    //创建过滤器链表对其进行链式调用
    return new DefaultGatewayFilterChain(combined).filter(exchange);
  }

loadFilters方法是将全局路由使用GatewayFilterAdapter包装成GatewayFilter

handle方法

  • 获取当前请求使用的路由Route
  • 获取路由配置的过滤器集合route.getFilters()
  • 合并全过滤器与路由配置过滤器combined
  • 对过滤器排序AnnotationAwareOrderComparator.sort
  • 通过过滤器集合构建顶级链表DefaultGatewayFilterChain,并对其当前请求调用链表的filter方法。

==备注==:

Spring-Cloud-Gateway的过滤器接口分为两种:

  • GlobalFilter : 全局过滤器,不需要在配置文件中配置,作用在所有的路由上,最终通过GatewayFilterAdapter包装成GatewayFilterChain可识别的过滤器
  • GatewayFilter : 需要通过spring.cloud.routes.filters 配置在具体路由下,只作用在当前路由上或通过spring.cloud.default-filters配置在全局,作用在所有路由上

至此,网关过滤器的整个结构以及加载使用流程源码已经阅读完毕,下篇重点学习下路由配置的过滤器加载创建流程

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • springcloud gateway聚合swagger2的方法示例

    问题描述 在搭建分布式应用时,每个应用通过nacos在网关出装配了路由,我们希望网关也可以将所有的应用的swagger界面聚合起来.这样前端开发的时候只需要访问网关的swagger就可以,而不用访问每个应用的swagger. 框架 springcloud+gateway+nacos+swagger 问题分析 swagger页面是一个单页面应用,所有的显示的数据都是通过和springfox.documentation.swagger.web.ApiResponseController进行数据交互,

  • 详解Spring Cloud Gateway 数据库存储路由信息的扩展方案

    动态路由背景 ​ 无论你在使用Zuul还是Spring Cloud Gateway 的时候,官方文档提供的方案总是基于配置文件配置的方式 例如: # zuul 的配置形式 routes: pig-auth: path: /auth/** serviceId: pig-auth stripPrefix: true # gateway 的配置形式 routes: - id: pigx-auth uri: lb://pigx-auth predicates: - Path=/auth/** filte

  • spring cloud如何修复zuul跨域配置异常的问题

    前言 本文主要给大家介绍一下在zuul进行跨域配置的时候出现异常该如何解决的方法,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 异常 The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed 实例 Access-Control-Allow-Credentials:true Access-Control-Allow-Credentials:t

  • springboot2.0和springcloud Finchley版项目搭建(包含eureka,gateWay,Freign,Hystrix)

    前段时间spring boot 2.0发布了,与之对应的spring cloud Finchley版本也随之而来了,两者之间的关系和版本对应详见我这边文章:spring boot和spring cloud对应的版本关系 项目地址:spring-cloud-demo spring boot 1.x和spring cloud Dalston和Edgware版本搭建的微服务项目现在已经很流行了,现在很多企业都已经在用了,这里就不多说了. 使用版本说明: spring boot 2.0.x spring

  • SpringCloud Gateway跨域配置代码实例

    这篇文章主要介绍了SpringCloud Gateway跨域配置代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 Springboot版本:2.1.8.RELEASE SpringCloud版本:Greenwich.SR2 yml配置: spring: cloud: gateway: globalcors: cors-configurations: '[/**]': # 允许携带认证信息 # 允许跨域的源(网站域名/ip),设置*为全部

  • SpringCloud Finchley Gateway 缓存请求Body和Form表单的实现

    在接入Spring-Cloud-Gateway时,可能有需求进行缓存Json-Body数据或者Form-Urlencoded数据的情况. 由于Spring-Cloud-Gateway是以WebFlux为基础的响应式架构设计,所以在原有Zuul基础上迁移过来的过程中,传统的编程思路,并不适合于Reactor Stream的开发. 网络上有许多缓存案例,但是在测试过程中出现各种Bug问题,在缓存Body时,需要考虑整体的响应式操作,才能更合理的缓存数据 下面提供缓存Json-Body数据或者Form

  • 详解SpringCloud Finchley Gateway 统一异常处理

    SpringCloud Finchley Gateway 统一异常处理 全文搜索[@@]搜索重点内容标记 1 . 问题:使用SpringCloud Gateway时,会出现各种系统级异常,默认返回HTML. 2 . Finchley版本的Gateway,使用WebFlux形式作为底层框架,而不是Servlet容器,所以常规的异常处理无法使用 翻阅源码,默认是使用DefaultErrorWebExceptionHandler这个类实现结构如下: 可以实现参考DefaultErrorWebExcep

  • Spring Cloud Gateway使用Token验证详解

    引入依赖 <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <ty

  • 详解SpringCloud Gateway之过滤器GatewayFilter

    在Spring-Cloud-Gateway之请求处理流程文中我们了解最终网关是将请求交给过滤器链表进行处理,接下来我们阅读Spring-Cloud-Gateway的整个过滤器类结构以及主要功能 通过源码可以看到Spring-Cloud-Gateway的filter包中吉接口有如下三个,GatewayFilter,GlobalFilter,GatewayFilterChain,下来我依次阅读接口的主要实现功能. GatewayFilterChain 类图 代码 /** * 网关过滤链表接口 * 用

  • 详解SpringCloud Gateway 2020.0.2最新版

    简述 官网:https://spring.io/projects/spring-cloud-gateway GitHub地址:https://github.com/spring-cloud/spring-cloud-gateway 本文编写自2021年4月7日,当前SpringCloud最新版本为2020.0.2版本 本文使用版本为 SpringCloud 版本2020.0.2 spring-cloud-starter-gateway版本3.0.2 spring-boot-starter版本2.

  • 详解SpringCloud新一代网关Gateway

    一.概述简介 1.1.简介 SpringCloud Gateway作为Spring Cloud生态系统中的网关,目标是替代Zuul,在Spring Cloud 2.0以上版本中,没有对新版本的Zuul 2.0以上最新高性能版本进行集成,仍然还是使用的Zuul 1.x非Reactor模式的老版本.而为了提升网关的性能,SpringCloud Gateway是基于WebFlux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty. Spring Cloud Gat

  • 详解SpringCloud服务认证(JWT)

     - JWT JWT(JSON Web Token), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景.JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密. - JWT与其它的区别 通常情况下,把API直接暴露出去是风险很大的,不说别的

  • 详解AngularJS中$filter过滤器使用(自定义过滤器)

    1.内置过滤器 * $filter 过滤器,是angularJs中用来处理数据以更好的方式展示给我用户.比如格式化日期,转换大小写等等. * 过滤器即有内置过滤器也支持自定义过滤器.内置过滤器很多,可以百度.关键是如何使用: * 1.在HTML中直接使用内置过滤器 * 2.在js代码中使用内置过滤器 * 3.自定义过滤器 * * (1)常用内置过滤器 * number 数字过滤器,可以设置保留数字小数点后几位等 * date 时间格式化过滤器,可自己设置时间格式 * filter 过滤的数据一般

  • 详解JSP中使用过滤器进行内容编码的解决办法

    详解JSP中使用过滤器进行内容编码的解决办法 问题 当通过JSP页面,向数据库中插入记录的时候,可能因为JSP页面编码原因,导致插入到数据库中的新纪录出现乱码.因此需要对JSP页面中的内容进行编码操作,从而保证与数据库中的编码一致. 解决方案 使用JSP中过滤器进行处理.处理步骤如下 1.新建一个servlet,使其实现javax.servlet.Filter接口 2.修改Servlet/JSP Mapping URL ,将其改为 /EncodingFilter 3.在EncodingFilte

  • 详解JavaWeb中的过滤器Filter

    一.什么是过滤器 1.Filter过滤器的作用:拦截请求 2.拦截请求常见场景: (1)权限检查 (2)日记操作 (3)事务管理 1.1 使用步骤 Filter 过滤器的使用步骤: 1.编写一个类去实现Filter 接口 2.实现过滤方法doFilter() 3.到web.xml 中去配置Filter 的拦截路径 二.初体验 web工程下新建一个admin目录,作为需要权限才能访问的目录,其中有两个文件 2.1 mynav.html <!DOCTYPE html> <html lang=

  • 详解Tomcat常用的过滤器

    一.跨域过滤器CorsFilter org.apcache.catalina.filters.CorsFilter是跨域资源共享规范的一个实现,常常用于前后端分离,静态资源与后端分离等情况.它主要在HttpServletResponse中增加Access-Control-*头,同时保护HTTP响应避免拆分,如果请求无效或者禁止访问,则返回403响应码. 1.1.配置示例 <filter> <filter-name>CorsFilter</filter-name> <

  • 详解SpringCloud的负载均衡

    目录 一.什么是负载均衡 二.负载均衡的简单分类 三.为什么需要做负载均衡 四.springCloud如何开启负载均衡 五.IRule 1.RandomRule:表示随机策略,它将从服务清单中随机选择一个服务: 2.ClientConfigEnabledRoundRobinRule:ClientConfigEnabledRoundRobinRule并没有实现什么特殊的处理逻辑,但是他的子类可以实现一些高级策略, 当一些本身的策略无法实现某些需求的时候,它也可以做为父类帮助实现某些策略,一般情况下

  • 详解SpringCloud微服务之Rest

    目录 一.什么是RestTemplate? 二.四种请求方式 2.1 GET请求 2.2 POST请求 2.3 PUT请求 2.4 DELETE请求 一.什么是RestTemplate? RestTemplate 是一个HTTP客户端,在Spring Cloud的服务调用方使用它我们可以方便的调用HTTP接口,支持GET.POST.PUT.DELETE等方法. 二.四种请求方式 首先注入Bean对象 @Configuration public class MyConfig { @Bean pub

随机推荐