Spring Cloud Alibaba學習筆記(20) - Spring Cloud Gateway 內置的全局過濾器


參考: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 返回的 ServiceInstanceisSecure 的值,會覆蓋請求的scheme。舉個例子,如果請求打到Gateway上使用的是 HTTPS ,但 ServiceInstanceisSecure 是false,那么下游微服務接收到的則是HTTP請求,反之亦然。另外,如果該路由指定了 GATEWAY_SCHEME_PREFIX_ATTR 屬性,那么前綴將會被剝離,並且路由URL中的scheme會覆蓋 ServiceInstance 的配置。

Netty Routing Filter

當請求進來時,NettyRoutingFilter 會查看一個URL,該URL是 exchange 的屬性 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 的值,如果該 url 的 scheme 是 httphttps ,那么該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請求會由NettyRoutingFilterWebClientHttpRoutingFilter添加這個屬性
  • 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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM