1. 程式人生 > >Spring Cloud gateway 閘道器服務二 斷言、過濾器

Spring Cloud gateway 閘道器服務二 斷言、過濾器

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

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

內建的斷言工廠

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

可以看到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:

  • 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過濾器都是預設的過濾器

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

可以通過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 閘道器服務 一

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

版權宣告:本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連結和本宣告。轉載請附帶公眾號二維