Spring Cloud Gateway WebFilter工廠 | Baeldung

banq發表於2020-05-21

Spring Cloud Gateway是微服務中經常使用的智慧代理服務。它透明地將請求集中在單個入口點中,並將其路由到適當的服務。它的一個最有趣的特點是概念過濾器(網頁過濾或GatewayFilter)。

WebFilter與謂詞工廠一起,包含完整的路由機制。Spring Cloud Gateway提供了許多內建的WebFilter工廠,這些工廠允許在到達代理服務之前與HTTP請求進行互動,並在將結果傳遞給客戶端之前與HTTP響應進行互動。也可以實現自定義過濾器

在本教程中,我們將重點介紹專案中包含的內建WebFilter工廠以及如何在高階用例中使用它們。

2. WebFilter工廠

網頁過濾(或GatewayFilter)工廠允許修改所述入站HTTP請求和出站HTTP響應。從這個意義上講,它提供了一組有趣的功能,可以在與下游服務互動之前和之後應用。

Spring Cloud Gateway WebFilter工廠 | Baeldung

處理程式會對映管理客戶端的請求。檢查請求是否與某些已配置的路由匹配。然後,將請求傳送到Web處理程式以執行此路由的特定篩選器鏈。虛線在前置和後置濾波器邏輯之間劃分邏輯。前置過濾器在代理請求之前執行。後置過濾器收到代理響應後便開始起作用。篩選器提供了在兩者之間修改流程的機制。

3.實施WebFilter工廠

讓我們回顧一下Spring Cloud Gateway專案中包含的最重要的WebFilter工廠。有兩種方法可以實現它們,即使用YAML或Java DSL。我們將展示有關如何同時實現這兩個示例。

3.1:HTTP請求

內建的WebFilter工廠允許與HTTP請求的標頭和引數進行互動。我們可以新增標頭值(AddRequestHeader), 對映標頭值(MapRequestHeader),設定或替換標頭值 (SetRequestHeader)  或刪除標頭值 (RemoveRequestHeader),並將其傳送到代理服務。原始主機標頭也可以保留(PreserveHostHeader)。

同樣,我們可以新增請求引數 (AddRequestParameter)和刪除請求引數 (RemoveRequestParameter),以供下游服務處理。讓我們看看如何做:

- id: add_request_header_route
  uri: https://httpbin.org
  predicates:
  - Path=/get/**
  filters:
  - AddRequestHeader=My-Header-Good,Good
  - AddRequestHeader=My-Header-Remove,Remove
  - AddRequestParameter=var, good
  - AddRequestParameter=var2, remove
  - MapRequestHeader=My-Header-Good, My-Header-Bad
  - MapRequestHeader=My-Header-Set, My-Header-Bad
  - SetRequestHeader=My-Header-Set, Set 
  - RemoveRequestHeader=My-Header-Remove
  - RemoveRequestParameter=var2

讓我們檢查一切是否按預期進行:

$ curl http://localhost:8080/get
{
  "args": {
    "var": "good"
  },
  "headers": {
    "Host": "localhost",
    "My-Header-Bad": "Good",
    "My-Header-Good": "Good",
    "My-Header-Set": "Set",
  },
  "origin": "127.0.0.1, 90.171.125.86",
  "url": "https://localhost:8080/get?var=good"
}

結果增加了My-Header-Good 、My-Header-Bad、My-Header-Set等標頭值。在args和url部分中,我們可以看到新增了一個新引數var。此外,最後一個過濾器將刪除var2引數。

此外,我們可以在到達代理服務之前修改請求正文。只能使用Java DSL表示法配置此過濾器。下面的程式碼段僅將響應正文的內容大寫,下面是使用https://httpbin.org/測試:

@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
     return builder.routes()
       .route("modify_request_body", r -> r.path("/post/**")
         .filters(f -> f.modifyRequestBody(
           String.class, Hello.class, MediaType.APPLICATION_JSON_VALUE, 
           (exchange, s) -> Mono.just(new Hello(s.toUpperCase()))))
         .uri("https://httpbin.org"))
       .build();
}

要測試程式碼段,讓我們使用-d選項執行curl ,看看內容是否有“ Content”:

$ curl -X POST "http://localhost:8080/post" -i -d "Content"
"data": "{\"message\":\"CONTENT\"}",
"json": {
    "message": "CONTENT"
}

我們可以看到,由於過濾器的原因,內容現在為大寫CONTENT。

3.2:HTTP響應

同樣,我們可以通過使用add(AddResponseHeader),設定或替換(SetResponseHeader),刪除(RemoveResponseHeader)和重寫(RewriteResponseHeader)來修改響應頭。響應上的另一個功能是重複資料刪除(DedupeResponseHeader)可以覆蓋策略並避免重複。通過使用另一個內建工廠(RemoveLocationResponseHeader),我們可以擺脫有關版本,位置和主機的特定於後端的詳細資訊。

- id: response_header_route
  uri: https://httpbin.org
  predicates:
  - Path=/header/post/**
  filters:
  - AddResponseHeader=My-Header-Good,Good
  - AddResponseHeader=My-Header-Set,Good
  - AddResponseHeader=My-Header-Rewrite, password=12345678
  - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
  - AddResponseHeader=My-Header-Remove,Remove
  - SetResponseHeader=My-Header-Set, Set
  - RemoveResponseHeader=My-Header-Remove
  - RewriteResponseHeader=My-Header-Rewrite, password=[^&]+, password=***
  - RewriteLocationResponseHeader=AS_IN_REQUEST, Location, ,

讓我們使用curl顯示響應頭:

$ curl -X POST "http://localhost:8080/header/post" -s -o /dev/null -D -
HTTP/1.1 200 OK
My-Header-Good: Good
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
My-Header-Rewrite: password=***
My-Header-Set: Set

與HTTP請求類似,我們可以修改響應正文。在此示例中,我們覆蓋了PUT響應的主體:

@Bean
public RouteLocator responseRoutes(RouteLocatorBuilder builder) {
    return builder.routes()
      .route("modify_response_body", r -> r.path("/put/**")
        .filters(f -> f.modifyResponseBody(
          String.class, Hello.class, MediaType.APPLICATION_JSON_VALUE, 
          (exchange, s) -> Mono.just(new Hello("New Body"))))
        .uri("https://httpbin.org"))
      .build();
}

讓我們使用PUT端點來測試功能:

$ curl -X PUT "http://localhost:8080/put" -i -d "CONTENT"
{"message":"New Body"}

3.3:路徑

內建WebFilter工廠提供的功能之一是與客戶端配置的路徑進行互動。可以設定其他路徑(SetPath),重寫(RewritePath),新增字首(PrefixPath)和剝離(StripPrefix)以僅提取其中的一部分。請記住,過濾器是根據其在YAML檔案中的位置順序執行的。讓我們看看如何配置路由:

- id: path_route
  uri: https://httpbin.org
  predicates:
  - Path=/new/post/**
  filters:
  - RewritePath=/new(?<segment>/?.*), $\{segment}
  - SetPath=/post

兩個過濾器在到達代理服務之前都刪除子路徑/ new。讓我們執行curl:

$ curl -X POST "http://localhost:8080/new/post" -i
"X-Forwarded-Prefix": "/new"
"url": "https://localhost:8080/post"

我們也可以使用StripPrefix工廠。通過StripPrefix = 1, 我們可以在聯絡下游服務時擺脫第一個子路徑。

3.4:與HTTP狀態有關

RedirectTo具有兩個引數:status和URL。狀態必須是一系列300重定向HTTP程式碼,而URL必須是有效的。SetStatus 採用一個引數狀態,該狀態可以是HTTP程式碼或其字串表示形式。讓我們看幾個例子:

- id: redirect_route
  uri: https://httpbin.org
  predicates:
  - Path=/fake/post/**
  filters:
  - RedirectTo=302, https://httpbin.org
- id: status_route
  uri: https://httpbin.org
  predicates:
  - Path=/delete/**
  filters:
  - SetStatus=401

第一個過濾器作用於/ fake / post路徑,並且客戶端以HTTP狀態302 重定向到https://httpbin.org:

$ curl -X POST "http://localhost:8080/fake/post" -i
HTTP/1.1 302 Found
Location: https://httpbin.org

第二個過濾器檢測到/ delete路徑,並設定了HTTP狀態401:

$ curl -X DELETE "http://localhost:8080/delete" -i
HTTP/1.1 401 Unauthorized

3.5:請求大小限制

最後,我們可以限制請求的大小限制(RequestSize)。如果請求大小超出限制,則閘道器拒絕訪問該服務:

- id: size_route
  uri: https://httpbin.org
  predicates:
  - Path=/anything
  filters:
  - name: RequestSize
    args:
       maxSize: 5000000

高階用例包括Spring Cloud Gateway提供了其他高階WebFilter工廠,以支援微服務模式的基準功能。例如斷路器、重試、儲存會話並保護標頭以及請求速率限制器。點選標題見原文高階用例詳情

 

相關文章