天天看點

Spring Cloud Gateway 過濾器詳解

作者:Doker多克

一、概述

Spring Cloud Gateway根據作用範圍劃分為:GatewayFilter和GlobalFilter

1、filter的作用和生命周期

由filter工作流程點,可以知道filter有着非常重要的作用,在“pre”類型的過濾器可以做參數校驗、權限校驗、流量監控、日志輸出、協定轉換等,在“post”類型的過濾器中可以做響應内容、響應頭的修改,日志的輸出,流量監控等

作用

網關過濾器用于攔截并鍊式處理Web請求,可以實作橫切與應用無關的需求,比如:鑒權、限流、日志輸出等

生命周期

Spring Cloud Gateway同zuul類似,有“pre”和“post”兩種方式的filter。用戶端的請求先經過“pre”類型的filter,然後将請求轉發到具體的業務服務,比如上圖中的user-service,收到業務服務的響應之後,再經過“post”類型的filter處理,最後傳回響應到用戶端。filter從作用範圍可分為另外兩種,一種是針對于單個路由的gateway filter,它在配置檔案中的寫法同predict類似;另外一種是針對于所有路由的global gateway filer

二、網關過濾器 GatewayFilter

過濾器允許以某種方式修改傳入的HTTP請求或傳出的HTTP響應。過濾器可以限定作用在某些特定請求路徑上。可以實作橫切與應用無關的需求,比如:安全、通路逾時的設定等。修改傳入的HTTP請求或傳出HTTP響應。Spring Cloud Gateway 包含許多内置的網關過濾器工廠,一共22個。包括頭部過濾器、路徑過濾器、Hystrix過濾器和重寫請求URL的過濾器,還有參數和狀态碼等其他類型的過濾器。根據過濾器工程的用途來劃分,可以分為以下幾種:Header、Parameter、Path、Body、Status、Session、Redirect、Retry、RateLimiter 和 Hystrix。 Spring Cloud Gateway包含許多内置的GatewayFilter工廠。

GatewayFilter工廠同上一篇介紹的Predicate工廠類似,都是在配置檔案application.yml中配置,遵循了約定大于配置的思想,隻需要在配置檔案配置GatewayFilter Factory的名稱,而不需要寫全部的類名,比如AddRequestHeaderGatewayFilterFactory隻需要在配置檔案中寫AddRequestHeader,而不是全部類名。在配置檔案中配置的GatewayFilter Factory最終都會相應的過濾器工廠類處理。

1、AddRequestHeader

描述

1、用于向下遊服務 添加 請求頭,

2、支援 uri variables

參數

1、name:向下遊服務傳遞請求頭的 key

2、value:向下遊服務傳遞請求頭的 value

示例

1、方式一、添加一個固定的請求頭

spring:
  cloud:
    nacos:
    gateway:
      routes:
        - id: product-provider-01
          uri: lb://product-provider
          predicates:
            - Path=/product/findOne
          filters:
            - AddRequestHeader=x-token,xxxxx
           

表示會向下遊服務傳遞一個 x-token 的請求頭,值是 xxxxx

2、配合 uri variables 添加動态請求頭

spring:
  cloud:
    gateway:
      routes:
        - id: product-provider-02
          uri: lb://product-provider
          predicates:
            - Path=/product/findOne/{productId}
          filters:
            - AddRequestHeader=x-token,xxxxx-{productId}
           

表示會向下遊服務傳遞一個 x-token 的請求頭,值是 xxxxx-比對上的productId的值

2、AddRequestParameter

描述

用于向下遊服務 添加一個請求參數

參數

name:添加的參數 key

value:添加的參數 value,可以支援 Path或Host 中的 uri variables

示例

spring:
  cloud:
    gateway:
      routes:
        - id: product-provider-01
          uri: lb://product-provider
          predicates:
            - Path=/product/findOne
          filters:
            - AddRequestParameter=username,zhangsan
           

向下遊服務增加一個 username = zhangsan 的請求參數

3、AddResponseHeader

描述

向下遊的響應中增加一個 響應頭。

參數

1、name:添加的響應頭的 key

2、value:添加的響應頭的 value,可以支援 Path或Host 中的 uri variables

示例

spring:
  cloud:
    gateway:
      routes:
        - id: product-provider-01
          uri: lb://product-provider
          predicates:
            - Path=/product/findOne
          filters:
            - AddResponseHeader=encryption,false
           

向下遊服務響應增加一個 encryption = false 的響應頭

4、DedupeResponseHeader

描述

移除重複的請求頭

參數

1、name:需要移除的重複的響應頭,多個以 空格 分隔

2、strategy:重複時,移除的政策,預設是RETAIN_FIRST,即保留第一個頭

  1. RETAIN_FIRST:保留第一個值
  2. RETAIN_LAST:保留最後一個值
  3. RETAIN_UNIQUE:保留所有的不重複的值

示例

spring:
  cloud:
    gateway:
      routes:
        - id: product-provider-01
          uri: lb://product-provider
          predicates:
            - Path=/product/findOne
          filters:
            - DedupeResponseHeader=x-token Access-Control-Allow-Credentials Access-Control-Allow-Origin,RETAIN_FIRST
           

移除上方指定的重複的響應頭,并且保留第一個出現的。

5、MapRequestHeader

描述

将 fromHeader 參數的值 追加到 toHeader 參數中。

  1. fromHeader 在 header 中不存在,那麼沒有什麼影響。
  2. fromHeader 存在
  3. toHeader 存在,那麼往配置中 toHeader 對應的 header 中追加 fromHeader對應的值
  4. toHeader 不存在,那麼往 header 中增加一個header ,key: 配置中的toHeader的值,value: fromHeader 在header中的值

參數

1、fromHeader:從請求參數中擷取header的值

2、toHeader:向header中設定一個 header, key是toheader的值,value 是 fromHeader的值

示例

spring:
  cloud:
    gateway:
      routes:
        - id: product-provider-01
          uri: lb://product-provider
          predicates:
            - Path=/product/findOne
          filters:
            - MapRequestHeader=from-header,x-token
           

即會向 request 中增加一個 key 為 x-token 的header ,值為 header 中 from-header 對應的值。(存在多種情況,參考描述)

6、Prefix

描述

為比對到的路由,在轉發到下遊服務時,增加一個字首prefix

參數

1、prefix:需要增加的路徑字首

示例

spring:
  cloud:
    gateway:
      routes:
        - id: product-provider-01
          uri: lb://product-provider
          predicates:
            - Path=/findOne
          filters:
            - PrefixPath=/product
           

通路 http://網關ip:port/findOne ⇒ 轉發到下遊服務位址 http://product-provider/product/findOne 增加了一個字首。

7、PreserveHostHeader

描述

它表示在Spring Cloud Gateway轉發請求的時候,保持用戶端的Host資訊不變,然後将它傳遞到下遊伺服器中。

參數

沒有參數

示例

spring:
  cloud:
    gateway:
      routes:
        - id: product-provider-01
          uri: lb://product-provider
          predicates:
            - Path=/product/findOne
          filters:
            - PreserveHostHeader
           

8、RemoveRequestHeader

描述

移除請求頭中的參數

參數

1、name:需要移除的請求頭

示例

spring:
  cloud:
    gateway:
      routes:
        - id: product-provider-01
          uri: lb://product-provider
          predicates:
            - Path=/product/findOne
          filters:
            - RemoveRequestHeader=x-token
           

9、RemoveResponseHeader

描述

移除響應頭

參數

1、name:需要移除的響應頭

示例

spring:
  cloud:
    gateway:
      routes:
        - id: product-provider-01
          uri: lb://product-provider
          predicates:
            - Path=/product/findOne
          filters:
            - RemoveResponseHeader=x-token
           

9、RemoveRequestParameter

描述

移除請求參數,往下遊服務傳遞時,此參數就沒有來

參數

1、name:需要移除的請求參數

示例

spring:
  cloud:
    gateway:
      routes:
        - id: product-provider-01
          uri: lb://product-provider
          predicates:
            - Path=/product/findOne
          filters:
            - RemoveRequestParameter=password
           

10、RewritePath

描述

根據正規表達式,執行路徑重寫

參數

1、regexp:比對的正規表達式

2、replacement:需要替換成的字元串

注意:

1、在yml配置中 $ 需要寫成 $\

2、路徑替換規則是: path.replaceAll(regexp,replacement)

示例

spring:
  cloud:
    gateway:
      routes:
        - id: product-provider-01
          uri: lb://product-provider
          predicates:
            - Path=/admin/product/findOne
          filters:
            - RewritePath=/admin(?<segment>/?.*), $\{segment} # 當通路/admin/product/findOne 将會替換成 /product/findOne
           

頁面上通路 /admin/product/findOne ⇒ 到達下遊服務的路徑是 /product/findOne

11、StripPrefix

描述

移除路徑字首,比如通路: /admin/aa/bb/cc 實際的下遊伺服器位址是 /bb/cc 則可以使用這個實作

參數

1、parts:請求的路徑按照/分隔後,需要跳過的部分,從1開始。

示例

spring:
  cloud:
    gateway:
      routes:
        - id: product-provider-01
          uri: lb://product-provider
          predicates:
            - Path=/admin/product/findOne
          filters:
            - StripPrefix=1 # 當通路/admin/product/findOne 将會替換成 /product/findOne
           

頁面上通路 /admin/product/findOne ⇒ 到達下遊服務的路徑是 /product/findOne

12、RequestSize

描述

配置請求體的大小,當請求體過大時,将會傳回 413 Payload Too Large。

參數

1、maxSize:請求體的大小

示例

spring:
  cloud:
    gateway:
      routes:
        - id: product-provider-01
          uri: lb://product-provider
          predicates:
            - Path=/product/findOne
          filters:
            - name: RequestSize
              args:
                maxSize: 1B
           

此處需要通過 filters[index].args.maxSize 配置,否則不生效。

13、ModifyRequestBody

描述

修改傳遞到下遊服務 RequestBody 的值,比如我們所有的經過網關的服務,到達下遊服務時,都需要将 使用者目前的使用者名和資料權限傳遞下去,此時就可以使用這個。

需求:

修改原始服務的參數,增加username和roles參數傳遞到下遊服務。

路由配置,隻可通過 Java 代碼來配置

@Configuration
public class RouteConfig {

    @Bean
    public RouteLocator routes(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("product-provider", predicateSpec -> predicateSpec.path("/product/modifyRequestBody")
                        .filters(gatewayFilterSpec -> gatewayFilterSpec.modifyRequestBody(String.class, Map.class, MediaType.APPLICATION_JSON_VALUE, (exchange, s) -> {
                            Map<String, Object> params = new HashMap<>(16);
                            params.put("old", s);
                            params.put("username", "v_huan");
                            params.put("roles", "ROLE_ADMIN");
                            return Mono.just(params);
                        })).uri("lb://product-provider")).build();
    }
}           

三、全局過濾器

全局過濾器不需要在配置檔案中配置,作用在所有的路由上,最終通過 GatewayFilterAdapter 包裝成 GatewayFilterChain 可識别的過濾器,它是請求業務以及路由的 URI 轉換為真實業務服務請求位址的核心過濾器,不需要配置系統初始化時加載,并作用在每個路由上。

當某個請求被路由比對時,那麼所有的全局過濾器(GlobalFilter)和路由比對到的 GatewayFilter會組合成一個過濾器鍊,排序規則是通過 Spring 的 Ordered 來排序。

GlobalFilter有pre和post2個執行階段,優先級越高 pre 階段執行越早, post階段執行越遲。

編寫一個全局過濾器需要實作 GlobalFilter 接口

下面這些是Gateway内置的全局過濾器,已經在所有路由生效

Spring Cloud Gateway 過濾器詳解

Spring Cloud Gateway根據作用範圍劃分為GatewayFilter和GlobalFilter,二者差別如下:

  • GatewayFilter : 需要通過spring.cloud.routes.filters 配置在具體路由下,隻作用在目前路由上或通過spring.cloud.default-filters配置在全局,作用在所有路由上
  • GlobalFilter : 全局過濾器,不需要在配置檔案中配置,作用在所有的路由上,最終通過GatewayFilterAdapter包裝成GatewayFilterChain可識别的過濾器,它為請求業務以及路由的URI轉換為真實業務服務的請求位址的核心過濾器,不需要配置,系統初始化時加載,并作用在每個路由上。

大家好,我是Doker品牌的Sinbad,歡迎點贊和評論,您的鼓勵是我們持續更新的動力!更多資料請前往Doker 多克