網關Spring Cloud Gateway科普

圖片



Spring Cloud Gateway是在Spring生態系統之上構建的API網關服務,它旨在提供一種簡單而有效的方式來對API進行路由,以及提供一些強大的過濾器功能, 例如:熔斷、限流、重試等。html

Spring Cloud Gateway 具備以下特性:spring

  • 基於Spring Framework 五、Project Reactor 和 Spring Boot 2.0 進行構建;
  • 動態路由:可以匹配任何請求屬性;
  • 能夠對路由指定 Predicate(斷言)和 Filter(過濾器);
  • 集成Hystrix的斷路器功能;
  • 集成 Spring Cloud 服務發現功能;
  • 易於編寫的 Predicate(斷言)和 Filter(過濾器);
  • 請求限流功能;
  • 支持路徑重寫。

Spring Cloud Gateway 做爲 Spring Cloud 生態系統中的網關,目標是替代 Zuul,在Spring Cloud 2.0以上版本中,沒有對新版本的Zuul 2.0以上最新高性能版本進行集成,仍然仍是使用的 Zuul 2.0以前的非Reactor模式的老版本。(有一個版本的說法是 Zuul2.x 的連續跳票和 Zuul1.x 的性能並非很理想,從而催生了Spring Cloud Gateway。)而爲了提高網關的性能,SpringCloud Gateway是基於WebFlux框架實現的,而WebFlux框架底層則使用了高性能的Reactor模式通訊框架Netty。json

網上不少地方都說 Zuul 是阻塞的,Spring Cloud Gateway 是非阻塞的,這麼說並不嚴謹的,準確的講 Zuul1.x 是阻塞的,而在2.x的版本中,Zuul也是基於Netty,也是非阻塞的,若是必定要說性能,其實這個真沒多大差距。Zuul的有關信息能夠參考《網關Zuul科普》。cookie

Spring Cloud Gateway有如下幾個重要的概念,後面的內容也主要圍繞這幾個概念展開。架構

  • Route(路由):路由是構建網關的基本模塊,它由ID,目標URI,一系列的斷言和過濾器組成,若是斷言爲true則匹配該路由;
  • Predicate(斷言):指的是Java 8 的 Function Predicate。輸入類型是Spring框架中的ServerWebExchange。這使開發人員能夠匹配HTTP請求中的全部內容,例如請求頭或請求參數。若是請求與斷言相匹配,則進行路由;
  • Filter(過濾器):指的是Spring框架中GatewayFilter的實例,使用過濾器,能夠在請求被路由先後對請求進行修改。

快速入門

定義2個服務:hello-server和user-server,他們分別都註冊到euraka服務上,示例以下:圖片app

在未通過網關時,咱們能夠經過如下2個接口來分別訪問hello-server和user-server:框架

http://localhost:8081/hello
http://localhost:8082/user

如今咱們來定義一個Spring Cloud Gateway服務,相關的Maven依賴以下:curl

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

application.yml文件中添加以下配置:ide

server:
 port: 9091
spring:
 application:
   name: spring-cloud-gateway
 cloud:
   gateway:
     routes:
       - id: path_route_1
         uri: http://localhost:8082/user
         predicates:
           - Path=/user

各字段含義以下:函數

  • id: 咱們自定義的路由ID,惟一。
  • uri:目標服務地址
  • predicates:路由條件,Predicate接受一個輸入參數,返回一個布爾值結果。該接口中包含多種默認方法來將Predicate組合成其餘複雜的邏輯(好比:與、或、非)

這段配置的意思是:配置了一個id爲 path_route_1的URI代理規則,當訪問地址 http://localhost:9091/user時,會路由到地址http://localhost:8082/user

Spring Cloud Gateway的路由配置和Zuul的路由配置有較大的區別,玩過Zuul的注意一下二者的區分。

啓動類以下,平平無奇:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {

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

如今咱們啓動Spring Cloud Gateway服務,而後請求http://localhost:9091/user:

hidden:~ hidden$ curl -i localhost:9091/user
HTTP/1.1 200 OK
Content-Type: text/plain;charset=UTF-8
Content-Length: 11
Date: Thu, 02 Apr 2020 09:28:58 GMT

User Info!

因爲沒有配置過hello-server的服務,因此還不能經過網關訪問它:

hidden:~ hidden$ curl -i localhost:9091/hello
HTTP/1.1 404 Not Found
Content-Type: application/json
Content-Length: 133

{"timestamp":"2020-04-02T09:30:09.840+0000","path":"/hello","status":404,"error":"Not Found","message":null,"requestId":"8b0a00e1-4"}

除了使用yml配置文件的方式,還能夠經過代碼(Java Bean)來實現路由配置。咱們在啓動類中添加方法 customRouteLocator() 來定製轉發規則,詳情以下:

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;

@SpringBootApplication
public class DemoApplication {

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

   @Bean
   public RouteLocator customRouteLocator(RouteLocatorBuilder builder){
       return builder.routes()
               .route("path_route_2", r -> r.path("/hello")
                       .uri("http://localhost:8081/hello"))
               .build();
   }
}

重啓服務,再次訪問hello-server的接口,能夠看到訪問成功:

hidden:~ hidden$ curl -i localhost:9091/hello
HTTP/1.1 200 OK
Content-Type: text/plain;charset=UTF-8
Content-Length: 19
Date: Thu, 02 Apr 2020 09:53:25 GMT

Hello!

路由規則

Spring Cloud Gateway將路由匹配做爲Spring WebFlux HandlerMapping基礎架構的一部分。Spring Cloud Gateway 包括許多內置的 Predicate 工廠,這些 Predicate 工廠經過不一樣的 HTTP 請求參數來匹配,多個 Predicate 工廠能夠組合使用。

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

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

說白了 Predicate 就是爲了實現一組匹配規則,方便讓請求過來找到對應的 Route 進行處理,接下來咱們接下 Spring Cloud GateWay 內置幾種 Predicate 的使用。

Cookie

帶有指定Cookie的請求會匹配改路由。將application.yml中的spring.cloud.gateway.routes配置修改成以下內容:

spring:
 application:
   name: spring-cloud-gateway
 cloud:
   gateway:
     routes:
       - id: cookie_route
         uri: http://localhost:8082/user
         predicates:
           - Cookie=username,pipisi

此時使用curl工具發送帶有cookie爲 username=pipisi 的請求就能夠匹配改路由:

curl -i localhost:9091/user --cookie "username=pipisi"

Query

帶指定查詢參數的請求能夠匹配該路由。將application.yml中的spring.cloud.gateway.routes配置修改成以下內容:

spring:
 application:
   name: spring-cloud-gateway
 cloud:
   gateway:
     routes:
       - id: cookie_route
         uri: http://localhost:8082/user
         predicates:
           - Query=username

此時使用curl工具發送帶有username=pipisi 查詢參數的請求就能夠匹配改路由:

curl -i localhost:9091/user?username=pipisi

其他的還有(參考上圖):經過Header匹配(將predicates中的 -Query 換成 -Header,如下類同)、經過Host匹配(-Host)、經過請求方法匹配(-Method)、經過IP地址匹配(-RemoteAddr)、經過請求時間(-After、-Before、-Between)、經過權重(-Weight)以及最開始在入門示例中就說起的經過請求路徑匹配(-Path)。還能夠進行組合使用,好比:

predicates:
 - Query=username
 - Cookie=username,pipisi
 - Path=/user

各類 Predicates 同時存在於同一個路由時,請求必須同時知足全部的條件才被這個路由匹配。

過濾器

網關常常須要對路由請求進行過濾,執行一些操做,如鑑權以後構造頭部之類的。過濾的種類不少,如增長請求頭、增長請求參數 、增長響應頭以及斷路器等等,這就用到了Spring Cloud Gateway 的 過濾器(Filter)。

當咱們有不少服務時,好比前面所說起的user-server和hello-server,客戶端請求各個服務的API接口時,每一個服務都要作相同的事情,好比鑑權、限流、日誌等,以下圖(上半部)。圖片

對於這樣重複的工做,能夠在微服務的上一層加一個全局的權限控制、限流、日誌的API網關服務,而後將請求轉發到具體的業務服務層。這個API網關服務就是起到一個服務邊界的做用,外界的請求訪問系統,必須先經過網關層,如上圖(下半部)。

Spring Cloud Gateway同 Zuul 相似,也有 pre 和 post 兩種方式的過濾器:pre 過濾器在請求被路由以前調用,咱們可利用這種過濾器實現身份驗證、在集羣中選擇請求的微服務、記錄調試信息等;post 過濾器在路由到微服務之後執行,這種過濾器可用來爲響應添加標準的 HTTP Header、收集統計信息和指標、將響應從微服務發送給客戶端等。

Spring Cloud Gateway的 Filter生命週期以下圖所示。圖片

與  Zuul  不一樣的是,Filter除了分爲pre 和 post 兩種方式的 Filter 外,在Spring Cloud Gateway中,Filter 根據做用範圍可分爲另外兩種,一種是針對於單個路由的 GatewayFilter,它在配置文件中的寫法同 Predicate相似;另一種是針對於全部路由的 GlobalFilter。

過濾器容許以某種方式修改傳入的HTTP Request 或傳出的HTTP Response,它能夠限定做用在某些特定請求路徑上。Spring Cloud Gateway包含了30多個內置的GatewayFilter工廠,好比AddRequestHeaderGatewayFilterFactory(添加請求頭的過濾器工廠)、AddRequestParameterGatewayFilterFactory(添加請求參數的過濾器工廠)、AddResponseHeaderGatewayFilterFactory(添加響應頭的過濾器工廠)、HystrixGatewayFilterFactory(Hystrix熔斷過濾器工廠)、RequestRateLimiterGatewayFilterFactory(請求限流的過濾器工廠)等(所有的GatewayFilter工廠能夠查看jar包中org.springframework.cloud.gateway.filter.factory目錄,除了這些,你也能夠自定義本身的過濾器)。

GatewayFilter工廠與前面介紹的Predicate工廠相似,都是在配置文件 application.yml 中配置,遵循了約定大於配置的思想,只須要在配置文件配置GatewayFilter Factory的名稱,而不須要寫所有的類名,好比 AddRequestHeaderGatewayFilterFactory 只須要在配置文件中寫AddRequestHeader,而不是所有類名。官方文檔都給出了這些過濾器工廠詳細的使用案例,下面挑選1個案例以做演示。

案例:AddRequestHeader

application.yml配置以下:

server:
 port: 9091
spring:
 application:
   name: spring-cloud-gateway
 cloud:
   gateway:
     routes:
       - id: cookie_route
         uri: http://localhost:8082/user
         filters:
           - AddRequestHeader=X-Request-Foo, Bar
         predicates:
           - Path=/user

過濾器工廠會在匹配的請求頭加上一對請求頭「x-request-foo=Bar」。能夠在下游的user-server服務中使用@RequestHeader來查看所接收請求的請求頭信息。

結合註冊中心Eureka使用

Zuul 做爲網關結合註冊中心進行使用時,默認狀況下 Zuul 會根據註冊中心註冊的服務列表,以服務名爲路徑建立動態路由,Spring Cloud Gateway一樣也實現了該功能。下面咱們演示下 Spring Cloud Gateway結合註冊中心如何使用默認的動態路由。

首先添加Maven依賴:

<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

其次修改application.yml配置文件:

server:
 port: 9091
spring:
 application:
   name: spring-cloud-gateway
 cloud:
   gateway:
     discovery:
       locator:
         enabled: true
         lower-case-service-id: true
eureka:
 client:
   service-url:
     defaultZone: http://localhost:8761/eureka/

重啓服務以後,咱們就能夠像 Zuul 那樣採用下面的方式訪問接口了:

http://localhost:9091/hello-server/hello
http://localhost:9091/user-server/user

工做原理圖片Spring Cloud Gateway 的核心處理流程如上圖,核心邏輯就是路由轉發,執行過濾器鏈。Gateway的客戶端迴向Spring Cloud Gateway發起請求,而後在 Gateway Handler Mapping 中找到與請求相匹配的路由,將其發送到 Gateway Web Handler。Handler 再經過指定的過濾器鏈來將請求發送到咱們實際的服務執行業務邏輯,而後返回。在Filter鏈中,經過虛線分割Filter的緣由是:過濾器能夠在轉發請求以前處理或者接收到被代理服務的返回結果以後處理。全部的Pre類型的Filter執行完畢以後,纔會轉發請求到被代理的服務處理。被代理的服務把全部請求完畢以後,纔會執行Post類型的過濾器。

References

  1. https://www.cnblogs.com/crazymakercircle/p/11704077.html
  2. http://www.imooc.com/article/297943
  3. https://www.cnblogs.com/bjlhx/p/9785926.html
  4. https://www.jianshu.com/p/17bbc8e10545



圖片



想知道更多?描下面的二維碼關注我

圖片

相關文章
相關標籤/搜索