參考:https://cloud.spring.io/spring-cloud-static/Greenwich.SR2/single/spring-cloud.html#_global_filters
全局過濾器 | 作用 |
---|---|
Combined Global Filter and GatewayFilter Ordering | 對過濾器執行順序進行排序 |
Forward Routing Filter | 用於本地forward,也就是將請求在Gateway服務內進行轉發,而不是轉發到下游服務 |
LoadBalancerClient Filter | 整合Ribbon實現負載均衡 |
Netty Routing Filter | 使用Netty的 HttpClient 轉發http、https請求 |
Netty Write Response Filter | 將代理響應寫回網關的客戶端側 |
RouteToRequestUrl Filter | 將從request里獲取的原始url轉換成Gateway進行請求轉發時所使用的url |
Websocket Routing Filter | 使用Spring Web Socket將轉發 Websocket 請求 |
Gateway Metrics Filter | 整合監控相關,提供監控指標 |
Marking An Exchange As Routed | 防止重復的路由轉發 |
Combined Global Filter and GatewayFilter Ordering
當Gateway接收到請求時,Filtering Web Handler 處理器會將所有的 GlobalFilter 實例以及所有路由上所配置的 GatewayFilter 實例添加到一條過濾器鏈中。該過濾器鏈里的所有過濾器都會按照 org.springframework.core.Ordered 注解所指定的數字大小進行排序。
Spring Cloud Gateway區分了過濾器邏輯執行的 ”pre” 和 ”post” 階段,所以優先級高的過濾器將會在 “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");
}));
};
}
返回結果:
first pre filter
second pre filter
third pre filter
first post filter
second post filter
third post filter
Forward Routing Filter
當請求進來時,ForwardRoutingFilter 會查看一個URL,該URL為 exchange 屬性 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 的值,如果該 url 的 scheme 是 forward(例如:forward://localendpoint),那么該Filter會使用Spirngd的DispatcherHandler 來處理這個請求。該請求的URL路徑部分,會被forward URL中的路徑覆蓋掉。而未修改過的原始URL,會被追加到 ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR 屬性中。
PS:所謂 url scheme 簡單來說就是 url 中的協議部分,例如http、https、ws等。自定義的 scheme 通常用於標識該url的行為,例如app開發中通常使用url scheme來跳轉頁面
LoadBalancerClient Filter
這個Filter是用來整合Ribbon的,其核心就是解析 scheme 為lb的 url,以此獲取微服務的名稱,然后再通過Ribbon獲取實際的調用地址。
當請求進來時,LoadBalancerClientFilter 會查看一個URL,該URL為 exchange 的屬性 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 的值,如果該 url 的 scheme 是 lb,(例如:lb://myservice ),那么該Filter會使用Spring Cloud的 LoadBalancerClient 來將 myservice 解析成實際的host 和 port ,並替換掉原本 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 屬性的值。而原始 url 會追加到 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(如上配置示例, 若 LoadBalancer 找不到名為 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 的配置。
Netty Routing Filter
當請求進來時,NettyRoutingFilter 會查看一個URL,該URL是 exchange 的屬性 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 的值,如果該 url 的 scheme 是 http 或 https ,那么該Filter會使用 Netty 的 HttpClient 向下游的服務發送代理請求。獲得的響應將放在 exchange 的 ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR 屬性中,以便在后面的 Filter 里使用。(有一個實驗性的過濾器: WebClientHttpRoutingFilter 可實現相同功能,但無需Netty)
Netty Write Response Filter
NettyWriteResponseFilter 用於將代理響應寫回網關的客戶端側,所以該過濾器會在所有其他過濾器執行完成后才執行,並且執行的條件是 exchange 中 ServerWebExchangeUtils.CLIENT_RESPONSE_CONN_ATTR 屬性的值不為空,該值為 Netty 的 Connection 實例。(有一個實驗性的過濾器: WebClientWriteResponseFilter 可實現相同功能,但無需Netty)
RouteToRequestUrl Filter
這個過濾器用於將從request里獲取的原始url轉換成Gateway進行請求轉發時所使用的url。當請求進來時,RouteToRequestUrlFilter 會從 exchange 中獲取 ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR 屬性的值,該值是一個 Route 對象。若該對象不為空的話,RouteToRequestUrlFilter 會基於請求 URL 及 Route 對象里的 URL 來創建一個新的 URL。新 URL 會被放到 exchange 的 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 屬性中。
如果 URL 具有 scheme 前綴,例如 lb:ws://serviceid ,該 lb scheme將從URL中剝離,並放到 ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR 中,方便后面的過濾器使用。
Websocket Routing Filter
該過濾器的作用與 NettyRoutingFilter 類似。當請求進來時,WebsocketRoutingFilter 會查看一個URL,該URL是 exchange 中 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 屬性的值,如果該 url 的 scheme 是 ws 或者 wss,那么該Filter會使用 Spring Web Socket 將 Websocket 請求轉發到下游。
另外,如果 Websocket 請求需要負載均衡的話,可為URL添加 lb 前綴以實現負載均衡,例如 lb:ws://serviceid 。
示例配置:
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/**
Gateway Metrics Filter
想要啟用Gateway Metrics Filter,需在項目中添加 spring-boot-starter-actuator 依賴,然后在配置文件中配置 spring.cloud.gateway.metrics.enabled 的值為true。該過濾器會添加名為 gateway.requests 的時序度量(timer metric),其中包含以下標記:
- routeId:路由ID
- routeUri:API將路由到的URI
- outcome:由 HttpStatus.Series 分類
- status:返回給客戶端的Http Status
- httpStatusCode:返回給客戶端的請求的Http Status
- httpMethod:請求所使用的Http方法
這些指標暴露在 /actuator/metrics/gateway.requests 端點中,並且可以輕松與 Prometheus 整合,從而創建一個 Grafana dashboard。
PS:Prometheus是一款監控工具,Grafana是一款監控可視化工具;Spring Boot Actuator可與這兩款工具進行整合。
Marking An Exchange As Routed
當一個請求走完整條過濾器鏈后,負責轉發請求到下游的那個過濾器會在 exchange 中添加一個 gatewayAlreadyRouted 屬性,從而將 exchange 標記為 routed(已路由)。一旦請求被標記為 routed ,其他路由過濾器將不會再次路由該請求,而是直接跳過。
了解了以上所有內置的全局過濾器后,我們知道不同協議的請求會由不同的過濾器轉發到下游。所以負責添加這個gatewayAlreadyRouted 屬性的過濾器就是最終負責轉發請求的過濾器:
- http、https請求會由NettyRoutingFilter或WebClientHttpRoutingFilter添加這個屬性
- forward請求會由ForwardRoutingFilter添加這個屬性
- websocket請求會由WebsocketRoutingFilter添加這個屬性
這些過濾器調用了以下方法將 exchange 標記為 routed ,或檢查 exchange 是否是 routed:- ServerWebExchangeUtils.isAlreadyRouted:檢查exchange是否為routed狀態
- ServerWebExchangeUtils.setAlreadyRouted:將exchange設置為routed狀態
簡單來說,就是Gateway通過 gatewayAlreadyRouted 屬性表示這個請求已經轉發過了,而無需其他過濾器重復路由,從而防止重復的路由轉發。
這些全局過濾器都有對應的配置類,感興趣的話可以查看相關源碼:
- org.springframework.cloud.gateway.config.GatewayAutoConfiguration
- org.springframework.cloud.gateway.config.GatewayMetricsAutoConfiguration
- org.springframework.cloud.gateway.config.GatewayLoadBalancerClientAutoConfiguration