转载

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

点击上方 "IT牧场" ,选择 "设为星标" 技术干货每日送达!

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速成(领域驱动设计速成)》 • 007: 全部 • 008: 加技术讨论群

往期精彩

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

想知道更多?长按/扫码关注我吧↓↓↓ Spring Cloud Gateway-全局过滤器(Global Filters) >>>技术讨论群<<< 喜欢就点个 "在看" 呗^_^

原文  http://mp.weixin.qq.com/s?__biz=MzI4ODQ3NjE2OA==&mid=2247485434&idx=2&sn=968ad77f7ec545ada73c5506df04f8b6
正文到此结束
Loading...