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

參考:https://cloud.spring.io/spring-cloud-static/Greenwich.SR2/single/spring-cloud.html#_global_filtershtml

全局過濾器 做用
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」 階段最後執行。web

  • 數字越小越靠前執行

示例代碼:spring

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

返回結果:websocket

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 屬性中。app

PS:所謂 url scheme 簡單來講就是 url 中的協議部分,例如http、https、ws等。自定義的 scheme 一般用於標識該url的行爲,例如app開發中一般使用url scheme來跳轉頁面負載均衡

LoadBalancerClient Filter

這個Filter是用來整合Ribbon的,其核心就是解析 scheme 爲lb的 url,以此獲取微服務的名稱,而後再經過Ribbon獲取實際的調用地址。socket

當請求進來時,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-boot

示例配置:微服務

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
相關文章
相關標籤/搜索