Spring Cloud Gateway-全局过滤器(Global Filters)

TIPS

本文基于Spring Cloud Gateway SR2,理论适配Spring Cloud Gateway SR1以及更高版本。

本文详细探讨Spring Cloud Gateway内置的全局过滤器。包括:

•Combined Global Filter and GatewayFilter Ordering

•Forward Routing Filter

•LoadBalancerClient Filter

•Netty Routing Filter

•Netty Write Response Filter

•RouteToRequestUrl Filter

•Websocket Routing Filter

•Gateway Metrics Filter

•Marking An Exchange As Routed

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

TIPS

官方声明:GlobalFilter的接口定义以及用法在未来的版本可能会发生变化。

个人判断:GlobalFilter可用于生产;如果有自定义GlobalFilter的需求,理论上也可放心使用——未来即使接口定义以及使用方式发生变化,应该也是平滑过渡的(比如Zuul的Fallback,原先叫ZuulFallbackProvider,后来改叫FallbackProvider,中间就有段时间新旧使用方式都支持,后面才逐步废弃老的使用方式)。

1 Combined Global Filter and GatewayFilter Ordering

当请求到来时,Filtering Web Handler 处理器会添加所有 GlobalFilter 实例和匹配的 GatewayFilter 实例到过滤器链中。

过滤器链会使用 org.springframework.core.Ordered 注解所指定的顺序,进行排序。Spring Cloud Gateway区分了过滤器逻辑执行的”pre”和”post”阶段,所以优先级高的过滤器将会在pre阶段最先执行,优先级最低的过滤器则在post阶段最后执行。

TIPS

数值越小越靠前执行,记得这一点就OK了。

示例代码:

@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");
}));
};
}

执行结果:

first pre filter
second pre filter
third pre filter
first post filter
second post filter
third post filter

2 Forward Routing Filter

ForwardRoutingFilter 会查看exchange的属性 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 的值(一个URI),如果该值l的scheme是 forward,比如:forward://localendpoint,则它会使用Spirng的DispatcherHandler 处理该请求。请求URL的路径部分,会被forward URL中的路径覆盖。未修改的原始URL,会被追加到 ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR 属性中。

TIPS

这段文档太学术了,讲解了LoadBalancerClientFilter 的实现原理,对使用者来说,意义不大;对使用者来说,只要知道这个Filter是用来做本地forward就OK了。

建议:如对原理感兴趣的,建议直接研究源码,源码比官方文档好理解。

3 LoadBalancerClient Filter

LoadBalancerClientFilter 会查看exchange的属性 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 的值(一个URI),如果该值的scheme是 lb,比如:lb://myservice ,它将会使用Spring Cloud的LoadBalancerClient 来将 myservice 解析成实际的host和port,并替换掉 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 的内容。原始地址会追加到 ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR 中。该过滤器还会查看 ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR 属性,如果发现该属性的值是 lb ,也会执行相同逻辑。

示例:

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

默认情况下,如果无法在 LoadBalancer 找到指定服务的实例,那么会返回503(对应如上的例子,找不到service实例,就返回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 的配置

TIPS

这段文档太学术了,讲解了LoadBalancerClientFilter 的实现原理,对使用者来说,意义不大;对使用者来说,其实只要知道这个Filter是用来整合Ribbon的就OK了

建议:如对原理感兴趣的,建议直接研究源码,源码比官方文档好理解。

4 Netty Routing Filter

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

5 Netty Write Response Filter

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

6 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 中,方便后面的过滤器使用。

7 Websocket Routing Filter

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

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

如果你使用 SockJS[1]

所谓普通http的后备,则应配置正常的HTTP路由以及Websocket路由。

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/**

8 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

[3] dashboard[4]

TIPS

Prometheus是一款监控工具,Grafana是一款监控可视化工具;Spring Boot Actuator可与这两款工具进行整合。关于整合,笔者写过手把手的博客,有兴趣可以看一下:

Spring Boot 2.x监控数据可视化(Actuator + Prometheus + Grafana手把手)[5]

9 Marking An Exchange As Routed

在网关路由 ServerWebExchange 后,它将通过在exchange添加一个 gatewayAlreadyRouted 属性,从而将exchange标记为 routed 。一旦请求被标记为 routed ,其他路由过滤器将不会再次路由请求,而是直接跳过。您可以使用便捷方法将exchange标记为 routed ,或检查exchange是否是 routed 。

•ServerWebExchangeUtils.isAlreadyRouted 检查是否已被路由

•ServerWebExchangeUtils.setAlreadyRouted 设置routed状态

TIPS

简单来说,就是网关通过 gatewayAlreadyRouted 属性表示这个请求已经转发过了,而无需其他过滤器重复路由。从而防止重复的路由操作。

参考文档

•114. Global Filters[6]

干货分享

最近将个人学习笔记整理成册,使用PDF分享。关注我,回复如下代码,即可获得百度盘地址,无套路领取!

•001:《Java并发与高并发解决方案》学习笔记;

•002:《深入JVM内核——原理、诊断与优化》学习笔记;

•003:《Java面试宝典》

•004:《Docker开源书》

•005:《Kubernetes开源书》

•006:《DDD速成(领域驱动设计速成)》

References

[1] SockJS: https://github.com/sockjs

[2] HttpStatus.Series: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/HttpStatus.Series.html

[3] Grafana: https://cloud.spring.io/spring-cloud-gateway/reference/html/images/gateway-grafana-dashboard.jpeg

[4] dashboard: https://cloud.spring.io/spring-cloud-gateway/reference/html/gateway-grafana-dashboard.json

[5] Spring Boot 2.x监控数据可视化(Actuator + Prometheus + Grafana手把手): http://www.itmuch.com/spring-boot/actuator-prometheus-grafana/

[6] 114. Global Filters: https://cloud.spring.io/spring-cloud-static/Greenwich.SR2/single/spring-cloud.html#_global_filters


分享到:


相關文章: