目录

背景

什么是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 {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {log.info("custom global filter");return chain.filter(exchange);}@Overridepublic 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: myRouteuri: lb://servicepredicates:- 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();}@Slf4jpublic class AFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> 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;@Overridepublic int getOrder() {return HIGHEST_PRECEDENCE + 100;}}@Slf4jpublic class BFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> 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;@Overridepublic int getOrder() {return HIGHEST_PRECEDENCE + 200;}}@Slf4jpublic class CFilter implements GlobalFilter, Ordered {@Override public Mono<Void> 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;@Overridepublic 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 {@Overridepublic Mono<Void> 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");//获取headerString 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;@Overridepublic int getOrder() {return HIGHEST_PRECEDENCE;}
}

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

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

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

- id: service_provider_demo_route_filteruri: lb://service-provider-demopredicates:- Path=/filter/**filters:- RewritePath=/filter/(?<segment>.*), /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<Void> filter(ServerWebExchange var1, WebFilterChain var2),所以,我们要使用 WebFilter只需要实现这一个方法即可。

Configuration
@Order(-1)
public class MyWebFilter implements WebFilter {@Overridepublic Mono<Void> 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

Spring Cloud原理分析系列#Gateway#GlobalFilter vs GatewayFilter vs WebFilter相关推荐

  1. spring cloud 快速上手系列 -> 04-网关 Gateway -> 041-空的工程

    spring cloud 快速上手系列 系列说明:快速上手,一切从简,搭建一个简单的微服务框架,让新手可以在这个基础框架上做各种学习.研究. 04-网关 Gateway 041-空的工程 1,说明 网 ...

  2. Spring Cloud微服务系列-Eureka Client源码解析(二)

    导语   上一篇博客中介绍了关于Eureka Client源码的基础部分,如果对于基础部分不是很了解的读者可以点击下面的连接进入到源码分析一中,从头开始学习 Spring Cloud微服务系列 Dis ...

  3. routing zuul_金三银四跳槽季快到了:送上Spring cloud全家桶系列之Zuul

    一.前言 金三银四跳槽季快到了:送上Spring cloud全家桶系列之Eureka 金三银四跳槽季快到了:送上Spring cloud全家桶系列之Feign 金三银四跳槽季快到了:送上Spring ...

  4. spring ioc原理分析

    spring ioc原理分析 spring ioc 的概念 简单工厂方法 spirng ioc实现原理 spring ioc的概念 ioc: 控制反转 将对象的创建由spring管理.比如,我们以前用 ...

  5. 浅谈:Spring Boot原理分析,切换内置web服务器,SpringBoot监听项目(使用springboot-admin),将springboot的项目打成war包

    浅谈:Spring Boot原理分析(更多细节解释在代码注释中) 通过@EnableAutoConfiguration注解加载Springboot内置的自动初始化类(加载什么类是配置在spring.f ...

  6. Spring Cloud微服务系列文,服务调用框架Feign

    之前博文的案例中,我们是通过RestTemplate来调用服务,而Feign框架则在此基础上做了一层封装,比如,可以通过注解等方式来绑定参数,或者以声明的方式来指定请求返回类型是JSON.    这种 ...

  7. Spring源码分析系列——bean创建过程分析(三)——工厂方法创建bean

    前言 spring创建bean的方式 测试代码准备 createBeanInstance()方法分析 instantiateUsingFactoryMethod()方法分析 总结 spring创建be ...

  8. 【Spring Cloud 基础设施搭建系列】Spring Cloud Demo项目 将微服务运行在Docker上

    文章目录 将微服务运行在Docker上 使用Maven插件构建Docker镜像 使用Maven插件读取Dockerfile进行构建 将插件绑定在某个phase执行 参考 源代码 将微服务运行在Dock ...

  9. Spring Cloud 2.x系列之Feign整合断路器监控Hystrix Dashboard

    SVN多版本库环境的搭建 OAuth 2.0是什么?看这篇文章就够了. 前端 Java Python等资源合集大放送 Ribbon可以整合整合断路器监控Hystrix Dashboard,Feign也 ...

  10. spring cloud 快速上手系列 -> 02-配置中心 Config -> 022-Config客户端

    spring cloud 快速上手系列 系列说明:快速上手,一切从简,搭建一个简单的微服务框架,让新手可以在这个基础框架上做各种学习.研究. 02-配置中心 Config 022-Config客户端 ...

最新文章

  1. Java程序员必看!2021Java大厂面试知识分享
  2. 服务器读取本地文件,java远程服务器访问本地文件
  3. JSON与Java对象的互相转换
  4. dell屏幕亮度调节不了_?戴尔XPS13 7390笔电测评:10代酷睿加持,屏幕/散热/续航升级...
  5. Dekker互斥算法解析
  6. python美女源代码_单身程序员,每晚用python抓取百万张美女图片,连女友都不想找了...
  7. iOS开发-当APP涉及到用户敏感信息适配Xcode9及(ios11)
  8. java集合之Stack栈基础
  9. RS485最大通讯距离和RS485接口定义
  10. 计算机二级机试题型,计算机二级机试题库
  11. excle表格导出到本地
  12. Computer Network Note
  13. 高盛:人工智能报告中文版
  14. 第九章 姜小白大难不死登君位 公子纠迟来一步梦成空
  15. 详解Object.create(null)(转载自https://juejin.cn/post/6844903589815517192)
  16. unity 摄像头跟着鼠标移动_unity第三视角移动,摄像机跟随
  17. ToggleButton图片按钮的两种制作方法
  18. 计算机专业考MBA有优势吗,工作后考mba有什么好处
  19. C#写的QQ找茬外挂
  20. 微信小程序家庭记账本开发进度七

热门文章

  1. win10设置计算机关机时间,教你windows10电脑怎么设置定时关机
  2. log4j2 的使用【超详细图文】
  3. Could not resolve placeholder
  4. 华为员工违规领夜宵被发现后,被罚冻薪降考评,终身不得领夜宵,HR:哪个员工上班健身,定性考勤造假...
  5. netware php_服务器_如何在 Netware 服务器中安装多块网卡,如果网络在扩大时服务器只装 - phpStudy...
  6. 怎么攻击一个网站服务器ip,服务器被不同的IP攻击怎么破?
  7. php 随机经纬度,使用php,API自动获取经纬度
  8. 大理古城“八戒”“悟空”与游客互殴 警方已介入
  9. 1068. Find More Coins (30)搜索题
  10. 10款优秀的在线格式转化器