Spring Cloud Gateway的路由,過濾器和限流

Spring 官方最終還是按捺不住推出了自己的網關組件:Spring Cloud Gateway ,相比之前我們使用的 Zuul(1.x) 它有哪些優勢呢?Zuul(1.x) 基於 Servlet,使用阻塞 API,它不支持任何長連接,如 WebSockets,Spring Cloud Gateway 使用非阻塞 API,支持 WebSockets,支持限流等新特性。

Spring Cloud Gateway

Spring Cloud Gateway 是 Spring Cloud 的一個全新項目,該項目是基於 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技術開發的網關,它旨在爲微服務架構提供一種簡單有效的統一的 API 路由管理方式。

注意:
Spring Cloud Gateway是基於Spring Boot 2.x, Spring WebFlux和Project Reactor 構建的。因此,在使用Spring Cloud Gateway時,許多不熟悉的同步庫(例如,Spring Data和Spring Security)和模式可能不適用。如果您對這些項目不熟悉,建議您在使用Spring Cloud Gateway之前先閱讀它們的文檔,以熟悉一些新概念。
Spring Cloud Gateway需要Spring Boot和Spring Webflux提供的Netty運行時。它不能在傳統的Servlet容器中或作爲WAR構建。

Spring Cloud Gateway 作爲 Spring Cloud 生態系統中的網關,目標是替代 Netflix Zuul,其不僅提供統一的路由方式,並且基於 Filter 鏈的方式提供了網關基本的功能,例如:安全,監控/指標,和限流。
在這裏插入圖片描述
Spring Cloud Gateway 的特徵:

  • 基於 Spring Framework 5,Project Reactor 和 Spring Boot 2.0
    動態路由
  • Predicates 和 Filters 作用於特定路由
  • 集成 Hystrix 斷路器
  • 集成 Spring Cloud DiscoveryClient
  • 易於編寫的 Predicates 和 Filters
  • 限流
  • 路徑重寫

相關概念:

  • Route(路由):這是網關的基本構建塊。它由一個 ID,一個目標 URI,一組斷言和一組過濾器定義。如果斷言爲真,則路由匹配。
  • Predicate(斷言):這是一個 Java 8 的 Predicate。輸入類型是一個 ServerWebExchange。我們可以使用它來匹配來自 HTTP 請求的任何內容,例如 headers 或參數。
  • Filter(過濾器):這是org.springframework.cloud.gateway.filter.GatewayFilter的實例,我們可以使用它修改請求和響應。

Spring Cloud Gateway 網關路由有兩種配置方式:

  • 在配置文件 yml 中配置
  • 通過@Bean自定義 RouteLocator,在啓動主類 Application 中配置
    這兩種方式是等價的,建議使用 yml 方式進配置。

pom.xml

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.6.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Finchley.SR2</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
</dependencies>

application.yml

server:
  port: 8080
spring:
  cloud:
    gateway:
      routes:
       - id: bamboo_route
        uri: https://blog.csdn.net/
        predicates:
        - Path=/blogdevteam

yml方式配置路由
id:我們自定義的路由 ID,保持唯一
uri:目標服務地址
predicates:路由條件,Predicate 接受一個輸入參數,返回一個布爾值結果。
該接口包含多種默認方法來將 Predicate 組合成其他複雜的邏輯(比如:與,或,非)。
filters:過濾規則,本示例暫時沒用。

啓動類:代碼方式配置路由

package com.bamboo;



import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;

/**
 * @program: spring-gateway
 * @description: Application
 * @author: Bamboo [email protected]
 * @create: 2019-10-26 20:00
 **/
@SpringBootApplication
public class Application {
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                // basic proxy
                .route(r -> r.path("/zjcjava")
                        .uri("https://blog.csdn.net//"))
                .build();
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

http://localhost:8080/zjcjava
對應訪問的地址是
https://blog.csdn.net/zjcjava

http://localhost:8080/blogdevteam
對應訪問的地址是
https://blog.csdn.net/blogdevteam

可以看出來,它會自動在url路徑/後面加上對應的路由地址

predicates路由斷言工廠

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

Predicate 來源於 Java 8,是 Java 8 中引入的一個函數,Predicate 接受一個輸入參數,返回一個布爾值結果。該接口包含多種默認方法來將 Predicate 組合成其他複雜的邏輯(比如:與,或,非)。可以用於接口請求參數校驗、判斷新老數據是否有變化需要進行更新操作。

在 Spring Cloud Gateway 中 Spring 利用 Predicate 的特性實現了各種路由匹配規則,有通過 Header、請求參數等不同的條件來進行作爲條件匹配到對應的路由。網上有一張圖總結了 Spring Cloud 內置的幾種 Predicate 的實現。
在這裏插入圖片描述

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - After=2017-01-20T17:42:47.789-07:00[America/Denver]
        - Before=2017-01-20T17:42:47.789-07:00[America/Denver]
        - Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]
        - Cookie=chocolate, ch.p
        - Header=X-Request-Id, \d+
        - Host=**.somehost.org,**.anotherhost.org
        - Method=GET
        - Path=/foo/{segment},/bar/{segment}
        - Query=baz
        - RemoteAddr=192.168.1.1/24
      - id: weight_high
        uri: https://weighthigh.org
        predicates:
        - Weight=group1, 8
      - id: weight_low
        uri: https://weightlow.org
        predicates:
        - Weight=group1, 2

後路線斷言工廠:After=2017年1月20日17:42山區時間(丹佛)之後的所有請求匹配
路線斷言工廠之前:Before=2017年1月20日17:42山區時間(丹佛)之前的所有請求匹配。
路線斷言工廠之間- Between=2017年1月20日山區時間(丹佛)之後和2017年1月21日17:42山區時間(丹佛)之後的所有請求匹配
Cookie路線斷言工廠 Cookie=請求匹配一個名爲chocolatewho的值爲ch.p正則表達式匹配的cookie
標頭路由斷言工廠 - Header=匹配請求具有名爲X-Request-Id其值爲\d+正則表達式匹配(具有一個或多個數字的值)的標頭
主機路由斷言工廠 - Host=請求的Host標頭中包含值www.somehost.org或beta.somehost.org,則此路由將匹配www.anotherhost.org
方法路線斷言工廠 - Method=此路由將匹配GET方式的請求
路徑路線斷言工廠 - Path=將匹配:/foo/1或/foo/bar或/bar/baz
查詢路由斷言工廠 - Query=匹配請求包含baz查詢參數
RemoteAddr路由斷言工廠 - RemoteAddr=請求的遠程地址爲192.168.1.1/24之間的IP,則此路由將匹配192.168.1.10
權重路線斷言工廠 將約80%的流量轉發至weighthigh.org,並將約20%的流量轉發至weightlow.org

全局過濾器

該GlobalFilter接口具有與相同的簽名GatewayFilter。這些是特殊過濾器,有條件地應用於所有路由。(此界面和用法可能會在將來的里程碑中更改)。

全局過濾器和GatewayFilter的組合訂購
當請求進入(並與路由匹配)時,過濾Web處理程序會將的所有實例GlobalFilter和所有特定GatewayFilter於路由的實例添加到過濾器鏈中。該組合的過濾器鏈按org.springframework.core.Ordered接口排序,可以通過實現該getOrder()方法進行設置。

由於Spring Cloud Gateway區分了執行過濾器邏輯的“前”階段和“後”階段(請參閱:工作原理),因此優先級最高的過濾器將在“前”階段中處於第一個階段,而在“後”階段中處於最後一個階段“-相。

ExampleConfiguration.java


//放入application啓動類中main方法後面即可
@Bean
public CustomGlobalFilter tokenFilter() {
    return new CustomGlobalFilter();
}



/**
 * @program: spring-gateway
 * @description: 全局過濾器
 * @author: Bamboo [email protected]
 * @create: 2019-10-26 23:06
 **/
public class CustomGlobalFilter implements GlobalFilter, Ordered {

    private static final Logger log = LoggerFactory.getLogger(CustomGlobalFilter.class);
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("custom global filter.....................................");
        // 添加全局鑑權
        String token = exchange.getRequest().getQueryParams().getFirst("token");
        if (token == null || token.isEmpty()) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }

        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -1;
    }
}

這裏我創建了一個全局的鑑權過濾器,只有參數中帶有token值才能繼續,否則提示無權訪問
http://localhost:8080/zjcjava?token=aa

fGatewayFilter工廠

路由過濾器允許以某種方式修改傳入的HTTP請求或傳出的HTTP響應。路由過濾器適用於特定路由。Spring Cloud Gateway包括許多內置的GatewayFilter工廠。

filters配置

修改配置文件如下:抓喲是 path,filters

server:
  port: 8080
spring:
  application:
    name: spring-cloud-gateway
  cloud:
    gateway:
      routes:
      - id: bamboo_route
        uri: https://blog.csdn.net/
        predicates:
#        - Path=/blogdevteam
        - Path=/test/blogdevteam
        filters:
        - StripPrefix=1 #去掉前綴
        - AddResponseHeader=X-Response-Default-Foo, Default-Bar #返回消息頭添加head信息

StripPrefix=1 #去掉第1個前綴以/分割
AddResponseHeader返回報文消息頭添加head信息

這裏只列舉幾個重要的過濾器

Hystrix GatewayFilter工廠

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相匹配的控制器。

限流RequestRateLimiter GatewayFilter工廠

RequestRateLimiter GatewayFilter Factory使用一種RateLimiter實現來確定是否允許繼續當前請求。如果不是,HTTP 429 - Too Many Requests則返回狀態(默認)。
此過濾器採用一個可選keyResolver參數和特定於速率限制器的參數(請參見下文)。
keyResolver是實現KeyResolver接口的bean 。在配置中,使用SpEL按名稱引用bean。#{@myKeyResolver}是SpEL表達式,它引用名稱爲的bean myKeyResolver。

Redis RateLimiter
redis實現基於Stripe所做的工作。它需要使用spring-boot-starter-data-redis-reactiveSpring Boot啓動器。
使用的算法是令牌桶算法。

該redis-rate-limiter.replenishRate是多麼的每秒許多請求你希望用戶被允許做,沒有任何下降的請求。這是令牌桶被填充的速率。
redis-rate-limiter.burstCapacity是允許用戶在一個單一的第二做請求的最大數目。這是令牌桶可以容納的令牌數。將此值設置爲零將阻止所有請求。

通過在replenishRate和中設置相同的值,可以達到穩定的速率burstCapacity。設置burstCapacity大於可以允許臨時爆發replenishRate。在這種情況下,速率限制器需要在突發之間間隔一段時間(根據replenishRate),因爲2個連續的突發將導致請求丟失(HTTP 429 - Too Many Requests)。

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: requestratelimiter_route
        uri: https://example.org
        filters:
        - name: RequestRateLimiter
          args:
            redis-rate-limiter.replenishRate: 10
            redis-rate-limiter.burstCapacity: 20

配置文件

@Bean
KeyResolver userKeyResolver() {
    return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
}

這定義了每個用戶10的請求速率限制。允許20個併發,但是下一秒只有10個請求可用。這KeyResolver是一個簡單的獲取user請求參數的參數(注意:不建議在生產中使用)。

速率限制器也可以定義爲實現RateLimiter接口的Bean 。在配置中,使用SpEL按名稱引用bean。#{@myRateLimiter}是SpEL表達式,它引用名稱爲的bean myRateLimiter。

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: requestratelimiter_route
        uri: https://example.org
        filters:
        - name: RequestRateLimiter
          args:
            rate-limiter: "#{@myRateLimiter}"
            key-resolver: "#{@userKeyResolver}"

參考文檔

官方參考文檔
https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.0.RC1/reference/html/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章