Spring Gateway 全局过滤器 Global Filters
原文档地址:点这里
6. Global Filters
GlobalFilter接口和GatewayFilter接口都只有一个相同的方法,这些特殊的过滤器可以有条件的应用于所有的路由。(这些接口和用法在以后的版本中可能会被修改)。
6.1 Combined Global Filter and GatewayFilter Ordering(过滤器的执行顺序)
当一个请求到达一个Gateway的路由时,Filtering Web Handler会加载所有的GlobalFilter实例以及这个路由上配置的所有的GatewayFilter过滤器,然后组成一个完整的过滤链。这个过滤链中过滤器使用org.springframework.core.Ordered接口进行排序,可以通过实现Ordered接口中的getOrder()方法或直接使用@Order注解修改过滤器的顺序。
由于Spring Cloud Gateway分开执行“pre”和“post”的过滤器,(可以参考前面讲Gateway如何工作的章节),因此,优先级高的过滤器将先执行“pre”类型的过滤器,最后执行“post”类型的的过滤器,如下面代码所示:
@Bean @Order(-1) public GlobalFilter a() { return (exchange, chain) -> { log.info("first pre filter"); return chain.filter(exchange).then(Mono.fromRunnable(() -> { log.info("third post filter"); })); }; } @Bean @Order(0) public GlobalFilter b() { return (exchange, chain) -> { log.info("second pre filter"); return chain.filter(exchange).then(Mono.fromRunnable(() -> { log.info("second post filter"); })); }; } @Bean @Order(1) public GlobalFilter c() { return (exchange, chain) -> { log.info("third pre filter"); return chain.filter(exchange).then(Mono.fromRunnable(() -> { log.info("first post filter"); })); }; }
从上面的代码可以看出,“pre”类型的过滤器是在(exchanges,chain)->{}中执行的,而“post”类型的过滤器是在chain.filter(exchange).then(Mono.fromRunnable(()->{}))中执行的。
6.2 Forward Routing Filter
这个全局过滤器的实现类是:ForwardRoutingFilter,请求过来吧,它会从exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);获取路由配置的URI,如果这个URI是forward模式,过滤器会将请求转发到DispatcherHandler,然后匹配到网关本的请求路径之中,原来请求的URI将被forward的URI覆盖,原始的请求URI被存储到exchange的ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR属性之中。
例如下面的配置:
- id: forward_routing_filter uri: forward:///app order: 10000 predicates: - Path=/forwardFilter filters: - PrefixPath=/gateway
在spring-cloud-gateway中添加跳转的FowardRoutingFilterController,来用接收跳转之后的请求:
@RestController @RequestMapping("gateway") public class FowardRoutingFilterController { @RequestMapping("app") public String globalFilters() { return "Forward跳转成功"; } }
在浏览器中输入:http://localhost:8080/forwardFilter,在spring-cloud-gateway服务收到请求之后,会执行以下步骤:
- 根据请求路径/forwardFilter匹配到路由forward_routing-filter,并将请求跳转为:http://localhost:8080/app
- filters里面的PrefixPath配置请求改写为:http://localhost:8080/gateway/app
- ForwardRoutingFilter过滤器中判断路由中有foroward://前缀,将请求转发给DispatcherHandler
- DispatcherHandler匹配并转到spring-cloud-gateway服务中的contoller匹配的路径
为了方便看到路径的变化,我们可以定义一个全局的过滤器:MyGlobalFitlers ,如下面代码所示:
@Service public class MyGlobalFitlers implements GlobalFilter, Ordered{ private Logger logger = LoggerFactory.getLogger(MyGlobalFitlers.class); @Override public int getOrder() { return 10001; } @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { Object value = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR); Object after = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR); logger.debug("global filters:{},{}",value,after); return chain.filter(exchange); } }
在浏览器中输入:http://localhost:8080/forwardFilter,在控制台上日志可以看到前后不同的两个请求地址:
global filters:http://localhost:8080/gateway/app,[http://localhost:8080/app]
6.3 LoadBalancerClient Filter
这个全局过滤器的实现类是:LoadBalancerClientFilter,它是用来处理负载均衡的过滤器。在网关后面的服务可以启动多个服务实例,这个过滤器就是把请求根据均衡规则路由到某台服务实例上面。它从exchange的ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR属性中获取URI,如果这个URI的scheme是“lb”,如:lb://myserivce,它会使用spring cloud 的LoadBalancerClient解析myservice服务名,获取一个服务实例的host和port,并替换原来的客户端请求。原来请求的url会存储在exchange的ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR属性中。这个过滤器也会从exchange中获取ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR属性值,如果它的值也是“lb”,也会使用相同的规则路由。
如下面配置:
- id: balanceclient_route uri: lb://app-a predicates: - Path=/app-a/app/**
app-a是服务的名字,即spring.application.name的值 ,启动两个app-a的服务,在浏览器中输入http://localhost:8080/app-a/app/balance,点击多次,可以看到app-a的两个服务实例都有日志输入,说明每个实例都被请求到了,实现了负载均衡。
注意:默认情况下,如果LoadBalancer根据配置的实例名找不到有效的服务实例,返回状态码503,如果你想配置返回404,可以这样设置:
spring.cloud.gateway.loadbalancer.use404=true
另外,Loadbalancer找到的服务实例ServiceInstance的方法isSecure的值,会覆盖请求中的scheme,比如如果请求网关的url的scheme是https,但是isSecure的值是false,在转发请求的时候,请求url的scheme会变成http,反过来也是一样的。但是,如果exchange的GATEWAY_SCHEME_PREFIX_ATTR属性在网关配置中被指定某个值,那么这个值将会覆盖ServiceInstance的配置。
6.4 Netty Routing Filter
这个全局过滤器的实现类是:NettyRoutingFilter,这是一个优先级最低的过滤器,如果从exchange的ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR获取的URL的scheme是https或http,它将使用Netty的HttpClient创建向下执行的请求代理,请求返回的结果将存储在exchange的ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR属性中,过滤器链后面的过滤器可以从中获取返回的结果。(还有一个测试使用的过滤器,WebClientHttpRoutingFilter,它和NettyRoutingFilter的功能一样,但是不使用netty)。
6.5 Netty Write Response Filter
这个全局过滤器的实现类是:NettyWriteResponseFilter,它的优先级是最高的,它是“post”类型的过滤器。如果在exchange中ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR的属性存在HttpClientResponse,它会在所有的其它的过滤器执行完成之后运行,将响应的数据发送给网关的客户端。
6.6 RouteToRequestUrl Filter
这个全局过滤器的实现类是:RouteToRequestUrlFilter,它的作用是把浏览器的URL请求的Path路径添加到路由的URI之中,比如浏览器请求网关的URL是:http://localhost:8080/app-a/app/balance,路由的URI配置是:uri: lb://app-a,那么添加之后的路由的URI是:lb://app-a/app/balance,并将它存储在exchange的ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR属性之中。
6.7 Websocket Routing Filter
这个全局过滤器的实现类是:WebsocketRoutingFilter,它是用来路由WebScoket请求,在exchange的ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR的URI中,如果scheme是ws或wss,它会使用Spring Web Socket 模块转发WebSocket请求。WebSockets可以使用路由进行负载均衡,比如:lb:ws://serviceid
如果在客户端使用了SockJS,那么应该配置一个普通的Http路由。如下面配置所示:
spring: cloud: gateway: routes: # SockJS route - id: websocket_sockjs_route uri: http://localhost:3001 predicates: - Path=/websocket/info/** # Normwal Websocket route - id: websocket_route uri: ws://localhost:3001 predicates: - Path=/websocket/**
6.8 Gateway Metrics Filter
这个全局过滤器的实现类是:GatewayMetricsFilter,它用来统计一些网关的性能指标。需要添加spring-boot-starter-actuator的项目依赖,
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
默认情况下,只要spring.cloud.gateway.metrics.enabled设置不是false,这个过滤器就生效。这个过滤器会添加一个名字为“gateway.requests”和tags为如下的timer metric:
- routeId: 路由的id
- routeUri:被路由的URI
- outcome:被HttpStatus.Series标记的结果
- status : 返回给客户端的http状态码
这些指标可以通过/actuator/metrics/gateway.requests查看,但是需要开启权限,如下面application.yml配置:
management:
endpoints:
web:
exposure:
include: "*"
注意,如果网关一次都没有被请求过,这时请求/actuator/metrics/gateway.requests会返回404,网关必须被请求过一次,才会正常返回监控的一些指标。
而且网关的这些监控指标可以整合到Prometheus,创建一个Grafana dashboard。
Prometheus是一款监控工具,Grafana是一款监控可视化工具;Spring Boot Actuator可与这两款工具进行整合,需要添加micrometer-registry-prometheus依赖
<dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> </dependency>
第二件1.9元】草原传奇 白蘑牛肉酱180g*2瓶香辣牛肉酱蘑菇酱拌饭酱拌面酱内蒙特产 草原传奇白蘑牛肉酱 2瓶
6.9 Making An Exchange As Routed
如果网关已经路由过一个ServerWebExchange,它将标记这个exchange已经被路由过,记录在exchange的ServerWebExchangeUtils.GATEWAY_ALREADY_ROUTED_ATTR属性中。一旦被标记完成了路由,其它的路由过滤器将不会再路由本次请求,直接跳过此过滤器。有两个方便的方法,你可以使用它们标记已路由过或检测是否已路由过
ServerWebExchangeUtils.isAlreadyRouted
takes aServerWebExchange
object and checks if it has been "routed"ServerWebExchangeUtils.setAlreadyRouted
takes aServerWebExchange
object and marks it as "routed"