栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring Cloud原理分析系列#Gateway#GlobalFilter vs GatewayFilter vs WebFilter

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring Cloud原理分析系列#Gateway#GlobalFilter vs GatewayFilter vs WebFilter

目录

背景

什么是GlobalFilter

定义全局过滤器

什么是GatewayFilter

定义局部过滤器

什么是WebFilter

Servlet之WebFilter注解

Spring之WebFilter接口

总结

WebFIlter和GlobalFIlter的区别

GatewayFilter和GlobalFIlter的区别

WebFIlter、GlobalFIlter、GatewayFilter总结

参考文章


背景

        最近在项目中看之前代码,发现一个网关filter模块大量使用各种Filter,但是深入分析感觉这些filter做的事情大多都是过滤、拦截、校验、转发、日志、改写等工作,所以想整理一篇文章分析分析这几个Filter背后的what、why、how。

        先看一下官网介绍Gateway的调用顺序,可以看到不管是GlobalFilter还是GatewayFilter都是在filter执行过程中执行的。

什么是GlobalFilter

GlobalFilter 接口和 GatewayFilter 有一样的接口定义,只不过, GlobalFilter 会作用于所有路由。

Global Filters:全局过滤器,不需要配置路由,系统初始化作用到所有路由上。

GatewayFilter:需要配置某个路由,才能过滤。如果需要使用全局路由,需要配置Default Filters。

官方声明:The  GlobalFilter interface has the same signature as  GatewayFilter. These are special filters that are conditionally applied to all routes.
 

When a request matches a route, the filtering web handler adds all instances of GlobalFilter and all route-specific instances of GatewayFilter to a filter chain. This combined filter chain is sorted by the org.springframework.core.Ordered interface, which you can set by implementing the getOrder() method.

As Spring Cloud Gateway distinguishes between “pre” and “post” phases for filter logic execution (see How it Works), the filter with the highest precedence is the first in the “pre”-phase and the last in the “post”-phase.

GlobalFilter的接口定义以及用法在未来的版本可能会发生变化。
当一个路由匹配到请求时,web 过滤器会将所有的GlobalFilter和当前路由指定的GatewayFilter添加到过滤器。组合顺序由org.springframework.core.Ordered决定。

官方使用:
@Bean
public GlobalFilter customFilter() {
    return new CustomGlobalFilter();
}

public class CustomGlobalFilter implements GlobalFilter, Ordered {

    @Override
    public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("custom global filter");
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -1;
    }
}

截止当前版本,官方定义了以下几个GlobalFilter,其具体功能如下:

  • Forward Routing Filter

    ForwardRoutingFilter 在exchange中查询 ServerWebExchangeUtils.GATEWAY_ REQUEST_ URL_ ATTR 属性, 如果 URL 为转发模式即 forward:/// localendpoint, 它将使用Spring DispatcherHandler 来处理请求。 未修改的原始 URL 将保存到 GATEWAY_ ORIGINAL_ REQUEST_ URL_ ATTR 属性的列表中。
    只要知道这个Filter是用来做本地forward就OK了

  • ReactiveLoadBalancerClientFilter

    ReactiveLoadBalancerClientFilter在exchange中查询ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR属性,如果URL有一个 lb 前缀 ,即 lb:// myservice,将使用 LoadBalancerClient 将名称 解析为实际的主机和端口,如示例中的 myservice。 未修改的原始 URL将保存到 GATEWAY_ ORIGINAL_ REQUEST_ URL_ ATTR 属性的列表中。过滤器还将查看。
    当服务没有找到ReactiveLoadBalancer时默认返回503,可以设置使用 spring.cloud.gateway.loadbalancer.use404=true.返回404.

    LoadBalancer 返回的 ServiceInstance 的 isSecure 的值,会覆盖请求的scheme。举个例子,如果请求打到Gateway上使用的是 HTTPS ,但 ServiceInstance 的 isSecure 是false,那么下游收到的则是HTTP请求,反之亦然。然而,如果该路由指定了 GATEWAY_SCHEME_PREFIX_ATTR 属性,那么前缀将会被剥离,并且路由URL中的scheme会覆盖 ServiceInstance 的配置
    对使用者来说,其实只要知道这个Filter是用来整合Ribbon的就OK了。

  • spring:
      cloud:
        gateway:
          routes:
          - id: myRoute
            uri: lb://service
            predicates:
            - Path=/service/**
  • Netty Routing Filter

    如果 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 的值的scheme是 http 或 https ,则运行Netty Routing Filter 。它使用Netty HttpClient 向下游发送代理请求。获得的响应将放在exchange的ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR 属性中,以便在后面的filter中使用。(有一个实验性的过滤器: WebClientHttpRoutingFilter 可实现相同功能,但无需Netty)

  • Netty Write Response Filter

    如果exchange中的 ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR 属性中有 HttpClientResponse ,则运行 NettyWriteResponseFilter 。该过滤器在所有其他过滤器执行完成后执行,并将代理响应协会网关的客户端侧。(有一个实验性的过滤器: WebClientWriteResponseFilter 可实现相同功能,但无需Netty)

  • RouteToRequestUrl Filter


    如果exchange中的ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR 属性中有一个 Route 对象,则运行 RouteToRequestUrlFilter 。它根据请求URI创建一个新URI,但会使用该 Route 对象的URI属性进行更新。新URI放到exchange的 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 属性中。如果URI具有scheme前缀,例如 lb:ws://serviceid ,该 lb scheme将从URI中剥离,并放到 ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR 中,方便后面的过滤器使用

  • Websocket Routing Filter

    如果exchange中的 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 属性的值的scheme是 ws或者 wss ,则运行Websocket Routing Filter。它底层使用Spring Web Socket将Websocket请求转发到下游。

    可为URI添加 lb 前缀实现负载均衡,例如 lb:ws://serviceid 。
     

  • Gateway Metrics Filter
    要启用Gateway Metrics,需添加 spring-boot-starter-actuator 依赖。然后,只要spring.cloud.gateway.metrics.enabled 的值不是false,就会运行Gateway Metrics Filter。此过滤器添加名为 gateway.requests 的时序度量(timer metric),其中包含以下标记:

    •routeId:路由ID

    •routeUri:API将路由到的URI

    •outcome:由 HttpStatus.Series[2] 分类

    •status:返回给客户端的Http Status

    •httpStatusCode:返回给客户端的请求的Http Status

    •httpMethod:请求所使用的Http方法

    这些指标暴露在 /actuator/metrics/gateway.requests 端点中,并且可以轻松与Prometheus整合,从而创建一个 Grafana。
    TIPSPrometheus是一款监控工具,Grafana是一款监控可视化工具;Spring Boot Actuator可与这两款工具进行整合。

  • Marking An Exchange As Routed
    在网关路由 ServerWebExchange 后,它将通过在exchange添加一个 gatewayAlreadyRouted 属性,从而将exchange标记为 routed 。一旦请求被标记为 routed ,其他路由过滤器将不会再次路由请求,而是直接跳过。您可以使用便捷方法将exchange标记为 routed ,或检查exchange是否是 routed 。
    ServerWebExchangeUtils.isAlreadyRouted 检查是否已被路由ServerWebExchangeUtils.setAlreadyRouted 设置routed状态
    TIPS简单来说,就是网关通过 gatewayAlreadyRouted 属性表示这个请求已经转发过了,而无需其他过滤器重复路由。从而防止重复的路由操作。

        实现 GlobalFilter 和 Ordered,重写相关方法,加入到spring容器管理即可,无需配置,全局过滤器对所有的路由都有效。

定义全局过滤器
@Configuration
public class FilterConfig {

    @Bean
    @Order(-1)
    public GlobalFilter a() {
        return new AFilter();
    }

    @Bean
    @Order(0)
    public GlobalFilter b() {
        return new BFilter();
    }

    @Bean
    @Order(1)
    public GlobalFilter c() {
        return new CFilter();
    }


    @Slf4j
    public class AFilter implements GlobalFilter, Ordered {

        @Override
        public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            log.info("AFilter前置逻辑");
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                log.info("AFilter后置逻辑");
            }));
        }

        //值越小,优先级越高
        //int HIGHEST_PRECEDENCE = -2147483648;
        //int LOWEST_PRECEDENCE = 2147483647;
        @Override
        public int getOrder() {
            return HIGHEST_PRECEDENCE + 100;
        }
    }

    @Slf4j
    public class BFilter implements GlobalFilter, Ordered {
        @Override
        public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            log.info("BFilter前置逻辑");
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                log.info("BFilter后置逻辑");
            }));
        }

        //值越小,优先级越高
        //int HIGHEST_PRECEDENCE = -2147483648;
        //int LOWEST_PRECEDENCE = 2147483647;
        @Override
        public int getOrder() {
            return HIGHEST_PRECEDENCE + 200;
        }
    }

    @Slf4j
    public class CFilter implements GlobalFilter, Ordered {

        @Override 
        public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            log.info("CFilter前置逻辑");
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                log.info("CFilter后置逻辑");
            }));
        }

        //值越小,优先级越高
        //int HIGHEST_PRECEDENCE = -2147483648;
        //int LOWEST_PRECEDENCE = 2147483647;
        @Override
        public int getOrder() {
            return HIGHEST_PRECEDENCE + 300;
        }
    }
}

什么是GatewayFilter

        GatewayFilter,正如上文描述,只是用于路由,这里就不做强调。官方定义了31种GatewayFilter,分别是。

  • AddRequestHeader
  • AddRequestParameter
  • AddResponseHeader
  • DedupeResponseHeader
  • CircuitBreaker
  • FallbackHeaders
  • MapRequestHeader
  • PrefixPath
  • PreserveHostHeader
  • RequestRateLimiter
  • RateLimiter
  • RedirectTo
  • RemoveRequestHeader
  • RemoveResponseHeader
  • RemoveRequestParameter
  • RewritePath
  • RewriteLocationResponseHeader
  • RewriteResponseHeader
  • SaveSession
  • SecureHeaders
  • SetPath
  • SetRequestHeader
  • SetResponseHeader
  • SetStatus
  • StripPrefix
  • Retry
  • RequestSize
  • SetRequestHostHeader
  • ModifyRequestBody
  • ModifyResponseBody
  • TokenRelay
  • Default

定义局部过滤器

步骤:

1、需要实现GatewayFilter, Ordered,实现相关的方法

2、加入到过滤器工厂,并且注册到spring容器中。

3、在配置文件中进行配置,如果不配置则不启用此过滤器规则。

局部过滤器举例, 对请求头部的 user-id 进行校验,代码如下:

1、需要实现GatewayFilter, Ordered,实现相关的方法

@Slf4j
public class UserIdCheckGateWayFilter implements GatewayFilter, Ordered {
    @Override
    public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String url = exchange.getRequest().getPath().pathWithinApplication().value();
        log.info("请求URL:" + url);
        log.info("method:" + exchange.getRequest().getMethod());
        //获取param 请求参数
        String uname = exchange.getRequest().getQueryParams().getFirst("uname");
        //获取header
        String userId = exchange.getRequest().getHeaders().getFirst("user-id");
        log.info("userId:" + userId);

        if (StringUtils.isEmpty(userId)) {
            log.info("*****头部验证不通过,请在头部输入  user-id");
            //终止请求,直接回应
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

    // 值越小,优先级越高
    //int HIGHEST_PRECEDENCE = -2147483648;
    //int LOWEST_PRECEDENCE = 2147483647;
    @Override
    public int getOrder() {
        return HIGHEST_PRECEDENCE;
    }
}

2、加入到过滤器工厂,并且注册到spring容器中。

@Component
public class UserIdCheckGatewayFilterFactory extends AbstractGatewayFilterFactory {
    
    @Override
    public GatewayFilter apply(Object config) {
        return new UserIdCheckGateWayFilter();
    }
}
 

3、在配置文件中进行配置,如果不配置则不启用此过滤器规则。

- id: service_provider_demo_route_filter
  uri: lb://service-provider-demo
  predicates:
    - Path=/filter/**
  filters:
    - RewritePath=/filter/(?.*), /provider/${segment}
    - UserIdCheck

什么是WebFilter

Servlet之WebFilter注解

        介绍完GlobalFilter和GatewayFilter之后,我们来看看上面是WebFIlter。如果说GlobalFilter是全局级别的Filter,GatewayFilter是路由级别的Filter,那么WebFilter就适合与Url级别。我们看一下WebFilter的配置,从名字可以看出其功能为对指定匹配的url进行过滤。

      @WebFilter(urlPatterns = "/lurl/api/*", filterName = "filteName")

Spring之WebFilter接口

WebFilter 是一个接口。里面只定义了一个方法。

Mono filter(ServerWebExchange var1, WebFilterChain var2),所以,我们要使用 WebFilter只需要实现这一个方法即可。

Configuration
@Order(-1)
public class MyWebFilter implements WebFilter {
    @Override
    public Mono filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) {

        ServerHttpRequest request =  serverWebExchange.getRequest();
        String token = request.getHeaders().getFirst("token");
        serverWebExchange.getAttributes().put("url","blog.csdn.net");
        return webFilterChain.filter(serverWebExchange);
    }

}

总结

WebFIlter和GlobalFIlter的区别
  •  GlobalFilter:GlobalFilter是spring.gateway里面定义的filter,其主要服务于gateway。

  •  WebFIlter:WebFilter是spring.web里面定义的,其主要用于web请求的过滤。SpringMVC中使用WebFliter接口,而在WebFlux中使用的是HandlerFilterFunction接口

GatewayFilter和GlobalFIlter的区别
  • GlobalFilter : 全局过滤器,不需要在配置文件中配置,作用在所有的路由上,系统初始化作用到所有路由上。最终通过GatewayFilterAdapter包装成GatewayFilterChain可识别的过滤器。

  • GatewayFilter : 需要通过spring.cloud.routes.filters 配置在具体路由下,只作用在当前路由上或通过spring.cloud.default-filters配置在全局,作用在所有路由上。需要配置某个路由,才能过滤。

WebFIlter、GlobalFIlter、GatewayFilter总结
  • WebFIlter是属于SpringBoot体现的,适用于Spring Web请求。GlobalFilter和GatewayFIlter属于SpringCloud体系的,适用于Spring Gateway中使用。
  • 从两个接口定义可以原理和思路大同小异,互相借鉴互相促进

参考文章

Spring Cloud Gateway

Spring Cloud Gateway GatewayFilter的使用 - 简书

Spring Cloud——微服务网关Spring Cloud GateWay - 简书

009-spring cloud gateway-过滤器GatewayFilter、GlobalFilter、GatewayFilterChain、作用、生命周期、GatewayFilterFactory内置过滤器 - bjlhx15 - 博客园

java - GlobalFilter vs WebFilter - Stack Overflow

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号