Spring Cloud gateway 網關服務二 斷言、過濾器

  • 2019 年 11 月 5 日
  • 筆記

微服務當前這麼火爆的程度,如果不能學會一種微服務框架技術。怎麼能升職加薪,增加簡歷的籌碼?spring cloud 和 Dubbo 需要單獨學習。說沒有時間?沒有精力?要學倆個框架?而Spring Cloud alibaba只需要你學會一個就會擁有倆種微服務治理框架技術。何樂而不為呢?加油吧!騷猿年

上一篇我們講述了gateway 的路由功能其實也類似與zuul服務的路由轉發。
今天主要講一下斷言機制。

內置的斷言工廠

介紹 Spring Cloud Gateway將路由作為Spring WebFlux HandlerMapping基礎架構的一部分進行匹配。Spring Cloud Gateway包括許多內置的Route Predicate工廠。所有這些斷言都與HTTP請求的不同屬性匹配。多個Route Predicate工廠可以合併,也可以通過邏輯合併

file

可以看到gateway 提供如此之多豐富的斷言,方式。

  • 比如說時間控住的,我們能想到秒殺場景。
  • ip 的我們能想到金絲雀測試
  • 權重我們可以使用灰度等等場景的應用

具體使用還得參照業務場景來選擇更適合我們的業務場景。

gateway 過濾器 分為全局過濾器,個性化過濾器

gateway 已經給我們提供了非常豐富的過濾器

  • AddRequestHeader GatewayFilter工廠採用名稱和值參數。

      這會將X-Request-Foo:Bar標頭添加到所有匹配請求的下游請求的標頭中。      spring:        cloud:            gateway:                routes:                - id: add_request_header_route                    uri: https://example.org                    filters:                    - AddRequestHeader=X-Request-Foo, Bar      AddRequestHeader知道用於匹配路徑或主機的URI變數。URI變數可用於該值,並將在運行時擴展。      spring:        cloud:            gateway:                routes:                - id: add_request_header_route                    uri: https://example.org                    predicates:                    - Path=/foo/{segment}                    filters:                    - AddRequestHeader=X-Request-Foo, Bar-{segment}

-AddResponseHeader GatewayFilter工廠採用名稱和值參數。

spring:      cloud:          gateway:              routes:              - id: add_request_parameter_route                  uri: https://example.org                  filters:                  - AddRequestParameter=foo, bar

這將添加foo=bar到所有匹配請求的下游請求的查詢字元串中。

AddRequestParameter知道用於匹配路徑或主機的URI變數。URI變數可用於該值,並將在運行時擴展。

spring:      cloud:          gateway:              routes:              - id: add_request_parameter_route                  uri: https://example.org                  predicates:                  - Host: {segment}.myhost.org                  filters:                  - AddRequestParameter=foo, bar-{segment}
  • AddResponseHeader GatewayFilter工廠採用名稱和值參數。

    spring:
    cloud:
    gateway:
    routes:
    – id: add_response_header_route
    uri: https://example.org
    filters:
    – AddResponseHeader=X-Response-Foo, Bar

    這會將X-Response-Foo:Bar標頭添加到所有匹配請求的下游響應的標頭中。

    AddResponseHeader知道用於匹配路徑或主機的URI變數。URI變數可用於該值,並將在運行時擴展。
    spring:
    cloud:
    gateway:
    routes:
    – id: add_response_header_route
    uri: https://example.org
    predicates:
    – Host: {segment}.myhost.org
    filters:
    – AddResponseHeader=foo, bar-{segment}

  • DedupeResponseHeader GatewayFilter工廠採用一個name參數和一個可選strategy參數。name可以包含標題名稱列表,以空格分隔。
    spring:
    cloud:
    gateway:
    routes:
    – id: dedupe_response_header_route
    uri: https://example.org
    filters:
    – DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin

    如果網關CORS邏輯和下游邏輯都添加了重複的值Access-Control-Allow-Credentials和Access-Control-Allow-Origin響應標頭,則這將刪除它們。

    DedupeResponseHeader過濾器還接受可選strategy參數。可接受的值為RETAIN_FIRST(默認值)RETAIN_LAST,和RETAIN_UNIQUE

  • Hystrix是Netflix的一個庫,用於實現斷路器模式。Hystrix GatewayFilter允許您將斷路器引入網關路由,保護您的服務免受級聯故障的影響,並允許您在下游故障的情況下提供後備響應
    要在項目中啟用Hystrix GatewayFilters,請spring-cloud-starter-netflix-hystrix從Spring Cloud Netflix添加依賴項。

    Hystrix GatewayFilter工廠需要一個name參數,它是的名稱HystrixCommand。
    spring:
    cloud:
    gateway:
    routes:
    – id: hystrix_route
    uri: https://example.org
    filters:
    – Hystrix=myCommandName

這會將其餘的過濾器包裝在HystrixCommand帶有命令名的中myCommandName。

Hystrix過濾器還可以接受可選fallbackUri參數。當前,僅forward:支援計劃的URI。如果調用了後備,則請求將被轉發到與URI相匹配的控制器。

    spring:          cloud:              gateway:                  routes:                  - id: hystrix_route                      uri: lb://backing-service:8088                      predicates:                      - Path=/consumingserviceendpoint                      filters:                      - name: Hystrix                          args:                              name: fallbackcmd                              fallbackUri: forward:/incaseoffailureusethis                      - RewritePath=/consumingserviceendpoint, /backingserviceendpoint

/incaseoffailureusethis調用Hystrix後備時,它將轉發到URI。請注意,此示例還通過lb目標URI 上的前綴演示了(可選)Spring Cloud Netflix Ribbon負載平衡。

主要方案是對fallbackUri網關應用程式中的內部控制器或處理程式使用。但是,也可以將請求重新路由到外部應用程式中的控制器或處理程式,如下所示:

    spring:          cloud:              gateway:                  routes:                  - id: ingredients                      uri: lb://ingredients                      predicates:                      - Path=//ingredients/**                      filters:                      - name: Hystrix                          args:                              name: fetchIngredients                              fallbackUri: forward:/fallback                  - id: ingredients-fallback                      uri: http://localhost:9994                      predicates:                      - Path=/fallback

在此示例中,fallback網關應用程式中沒有終結點或處理程式,但是另一個應用程式中有一個終結點或處理程式,在下註冊localhost:9994。

如果將請求轉發給後備,則Hystrix網關過濾器還會提供Throwable引起請求的。它已ServerWebExchange作為 ServerWebExchangeUtils.HYSTRIX_EXECUTION_EXCEPTION_ATTR屬性添加到,可以在網關應用程式中處理後備時使用。

對於外部控制器/處理程式方案,可以添加帶有異常詳細資訊的標頭。您可以在FallbackHeaders GatewayFilter Factory部分中找到有關它的更多資訊。

Hystrix設置(例如超時)可以使用全局默認值配置,也可以使用Hystrix Wiki上說明的應用程式屬性在逐條路由的基礎上進行配置。

要為上述示例路由設置5秒超時,將使用以下配置:

hystrix.command.fallbackcmd.execution.isolation.thread.timeoutInMilliseconds: 5000
  • 該FallbackHeaders工廠可以讓你在轉發到請求的頭部添加蝟執行異常的詳細資訊fallbackUri在以下情況下在外部應用程式
    spring:
    cloud:
    gateway:
    routes:
    – id: ingredients
    uri: lb://ingredients
    predicates:
    – Path=//ingredients/**
    filters:
    – name: Hystrix
    args:
    name: fetchIngredients
    fallbackUri: forward:/fallback
    – id: ingredients-fallback
    uri: http://localhost:9994
    predicates:
    – Path=/fallback
    filters:
    – name: FallbackHeaders
    args:
    executionExceptionTypeHeaderName: Test-Header

在此示例中,在運行時發生執行異常後HystrixCommand,該請求將轉發到在上fallback運行的應用中的端點或處理程式localhost:9994。具有異常類型,消息和-if available-根本原因異常類型和消息的標頭將由FallbackHeaders過濾器添加到該請求。

通過設置下面列出的參數的值及其默認值,可以在配置中覆蓋標頭的名稱:

- executionExceptionTypeHeaderName("Execution-Exception-Type")    - executionExceptionMessageHeaderName("Execution-Exception-Message")    - rootCauseExceptionTypeHeaderName("Root-Cause-Exception-Type")    - rootCauseExceptionMessageHeaderName("Root-Cause-Exception-Message")

您可以在Hystrix GatewayFilter Factory部分中找到有關Hystrix如何與Gateway一起工作的更多資訊。

  • MapRequestHeader GatewayFilter工廠採用’fromHeader’和’toHeader’參數。它創建一個新的命名標頭(toHeader),並從傳入的HTTP請求中從現有的命名標頭(fromHeader)中提取值。如果輸入標頭不存在,則過濾器不起作用。如果新的命名標頭已經存在,則其值將使用新值進行擴充。

      spring:        cloud:            gateway:                routes:                - id: map_request_header_route                    uri: https://example.org                    filters:                    - MapRequestHeader=Bar, X-Request-Foo

這會將X-Request-Foo:標頭添加到下游請求的標頭中,其中包含來自傳入的HTTP請求Bar標頭的更新值。

  • PrefixPath GatewayFilter工廠採用單個prefix參數。
    spring:
    cloud:
    gateway:
    routes:
    – id: prefixpath_route
    uri: https://example.org
    filters:
    – PrefixPath=/mypath

這將/mypath作為所有匹配請求的路徑的前綴。因此,對的請求/hello將發送給/mypath/hello。

  • PreserveHostHeader GatewayFilter工廠沒有參數。此過濾器設置請求屬性,路由過濾器將檢查該請求屬性,以確定是否應發送原始主機頭,而不是由HTTP客戶端確定的主機頭。

      spring:        cloud:            gateway:                routes:                - id: preserve_host_route                    uri: https://example.org                    filters:                    - PreserveHostHeader
  • RequestRateLimiter GatewayFilter Factory使用一種RateLimiter實現來確定是否允許繼續當前請求。如果不是,HTTP 429 – Too Many Requests則返回狀態(默認)。此過濾器採用一個可選keyResolver參數和特定於速率限制器的參數。

  • Redis RateLimiter GatewayFilter工廠 redis實現基於Stripe所做的工作。它需要使用spring-boot-starter-data-redis-reactiveSpring Boot啟動器。
  • RedirectTo GatewayFilter工廠採用status和url參數。狀態應該是300系列重定向http程式碼,例如301。URL應該是有效的URL。這將是Location標題的值
  • RemoveHopByHopHeadersFilter GatewayFilter工廠從轉發的請求中刪除標頭。被刪除的頭的默認列表來自IETF。
  • RemoveRequestHeader GatewayFilter工廠採用一個name參數。它是要刪除的標題的名稱。
  • RemoveResponseHeader GatewayFilter工廠採用一個name參數。它是要刪除的標題的名稱。
  • RemoveRequestParameter GatewayFilter工廠採用一個name參數。它是要刪除的查詢參數的名稱。
  • RewritePath GatewayFilter工廠採用路徑regexp參數和replacement參數。這使用Java正則表達式提供了一種靈活的方式來重寫請求路徑。
  • RewriteLocationResponseHeader GatewayFilter工廠Location通常會修改響應標頭的值,以擺脫後端特定的詳細資訊。這需要stripVersionMode,locationHeaderName,hostValue,和protocolsRegex參數。
  • 該RewriteResponseHeader GatewayFilter廠需要name,regexp和replacement參數。它使用Java正則表達式以靈活的方式重寫響應標頭值。
  • SaveSession GatewayFilter Factory 在向下游轉發呼叫之前強制執行WebSession::save操作。這在將Spring Session之類的東西與惰性數據存儲一起使用時特別有用,並且需要確保在進行轉發呼叫之前已保存會話狀態。
  • SetPath GatewayFilter工廠採用路徑template參數。通過允許路徑的模板段,它提供了一種操作請求路徑的簡單方法。這使用了Spring Framework中的uri模板。允許多個匹配段。
  • SetRequestHeader GatewayFilter工廠採用name和value參數。
  • SetResponseHeader GatewayFilter工廠採用name和value參數
  • SetStatus GatewayFilter工廠採用單個status參數。它必須是有效的Spring HttpStatus。它可以是整數值404或枚舉的字元串表示形式NOT_FOUND
  • StripPrefix GatewayFilter工廠採用一個參數parts。該parts參數指示在向下游發送請求之前,要從請求中剝離的路徑中的零件數
  • 重試GatewayFilter工廠
  • RequestSize GatewayFilter工廠 當請求大小大於允許的限制時,RequestSize GatewayFilter Factory可以限制請求到達下游服務。過濾器將RequestSize參數作為請求的允許大小限制(以位元組為單位
  • 修改請求正文GatewayFilter工廠 該過濾器被認為是BETA,API將來可能會更改 此過濾器可用於在網關將請求主體發送到下游之前修改請求主體。
  • 默認過濾器 如果您想添加過濾器並將其應用於所有路由,則可以使用spring.cloud.gateway.default-filters。該屬性採用過濾器列表
  • 全局過濾器 該GlobalFilter介面具有與相同的簽名GatewayFilter。這些是特殊過濾器,有條件地應用於所有路由。(此介面和用法可能會在將來的里程碑中更改)。
  • 全局過濾器和GatewayFilter的組合訂購

因為spring cloud gateway 提供的內置過濾器太多了。不在這裡一一介紹
可以查看官方的文檔 進行了解學習

gateway官方文檔

https://cloud.spring.io/spring-cloud-gateway/reference/html/

接下來講一下,全局過濾器GlobalFilter介面。

  • GlobalFilter 和 GatewayFilter 的 #filter(ServerWebExchange, GatewayFilterChain) 方法簽名一致;
  • GlobalFilter會作用於所有的路由上;
  • 在未來的里程碑版本中可能作一些調整;

可以看一下默認的實現的全局過濾器 ,除去AuthorizeFilter過濾器都是默認的過濾器

file

具體的裡面的作用,其實上面的已經有了簡單的描述不在複述。有興趣的同學可以看看裡面的實現,都是利用過濾器做轉發或者一些對流量請求的修改、鑒權、等操作

可以通過actuator 模組監控查詢 GlobalFilter實現類

1、pom引入spring-boot-starter-actuator 。因為之前就直接在parent pom 進行了引入操作。不再次引入

<dependency>      <groupId>org.springframework.boot</groupId>      <artifactId>spring-boot-starter-actuator</artifactId>  </dependency>

2、配置文件bootstrap.yml中開啟監控管理端點

  management:    endpoints:      web:        exposure:          include: "*"    endpoint:      health:        show-details: ALWAYS

3、請求瀏覽器 http://localhost:9000/actuator/gateway/globalfilters

{  org.springframework.cloud.gateway.filter.AdaptCachedBodyGlobalFilter@4b957db0: -2147482648,  org.springframework.cloud.gateway.filter.WebsocketRoutingFilter@273fa9e: 2147483646,  com.xian.cloud.filter.AuthorizeFilter@4b03cbad: 0,  org.springframework.cloud.gateway.filter.ForwardRoutingFilter@8840c98: 2147483647,  org.springframework.cloud.gateway.filter.NettyRoutingFilter@5c313224: 2147483647,  org.springframework.cloud.gateway.filter.NettyWriteResponseFilter@1e1e837d: -1,  org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter@5d71b500: 10000,  org.springframework.cloud.gateway.filter.LoadBalancerClientFilter@5b29ab61: 10100,  org.springframework.cloud.gateway.filter.GatewayMetricsFilter@527a8665: -2147473648,  org.springframework.cloud.gateway.filter.ForwardPathFilter@626b639e: 0  }

觀察這些實現類。都是實現 GlobalFilter、Ordered倆個介面
實現自己的全局過濾器

創建 AuthorizeFilter

package com.xian.cloud.filter;    import lombok.extern.slf4j.Slf4j;  import org.apache.commons.lang3.StringUtils;  import org.springframework.cloud.gateway.filter.GatewayFilterChain;  import org.springframework.cloud.gateway.filter.GlobalFilter;  import org.springframework.core.Ordered;  import org.springframework.http.HttpHeaders;  import org.springframework.http.server.reactive.ServerHttpRequest;  import org.springframework.stereotype.Component;  import org.springframework.web.server.ServerWebExchange;  import reactor.core.publisher.Mono;    /**   * <Description>   *   * @author [email protected]   * @version 1.0   * @createDate 2019/11/04 18:06   */  @Component  @Slf4j  public class AuthorizeFilter implements GlobalFilter, Ordered {          private static final String AUTHORIZE_TOKEN = "Authorization";      private static final String AUTHORIZE_UID = "uid";        @Override      public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {            ServerHttpRequest request = exchange.getRequest();          HttpHeaders headers = request.getHeaders();            ServerHttpRequest.Builder mutate = request.mutate();            String token = headers.getFirst( AUTHORIZE_TOKEN );          String uid = headers.getFirst( AUTHORIZE_UID );          String method = request.getMethodValue();            log.info( "AuthorizeFilter token 全局過濾器 token:{},uid:{}",token,uid );          if (token == null) {              token = request.getQueryParams().getFirst( AUTHORIZE_TOKEN );          }          if(StringUtils.isNotBlank(token)){                          //TODO 許可權驗證          }            return chain.filter( exchange );      }        @Override      public int getOrder() {          return 0;      }  }  

然後啟動服務。

curl http://localhost:9000/client/client/test
日誌列印

[2019-11-05 19:30:52.802] [INFO ] com.xian.cloud.filter.AuthorizeFilter - AuthorizeFilter token 全局過濾器 token:null,uid:null

下一篇我們將介紹訂製的過濾器,針對下游服務對應過濾器

摘自參考 spring cloud 官方文檔

示例程式碼地址

伺服器nacos 地址 http://47.99.209.72:8848/nacos

往期地址 spring cloud alibaba 地址

spring cloud alibaba 簡介

Spring Cloud Alibaba (nacos 註冊中心搭建)

Spring Cloud Alibaba 使用nacos 註冊中心

Spring Cloud Alibaba nacos 配置中心使用

spring cloud 網關服務

Spring Cloud zuul網關服務 一

Spring Cloud 網關服務 zuul 二

Spring Cloud 網關服務 zuul 三 動態路由

Spring Cloud alibaba網關 sentinel zuul 四 限流熔斷

Spring Cloud gateway 網關服務 一

如何喜歡可以關注分享本公眾號。
file

版權聲明:本文為部落客原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。轉載請附帶公眾號二維碼