微服務之服務網關Gateway


一、什么是Gateway?

  Gateway是Spring生產系統上構建的API服務網關,基於Spring5、SpringBoot2和ProjectReactor等技術。它的目標是提供一種簡單有效的方式對API進行路由,以及提供一些強大的過濾器功能,包括熔斷、限流、重試等。

  SpringCloud Gateway是SpringCloud的一個全新項目,基於WebFlux框架實現的,而webFlux底層使用了高性能的Reactor模式通信框架Netty。SpringCloud Gateway為微服務架構提供一種簡單有效的統一的API路由管理方式,目的是為了替代Zuul成為全新一代的服務網關。

  前面提到了服務網關,那什么又是服務網關呢?它是一個網絡關口、通道,是整個微服務平台所有請求的統一入口,所有的客戶端和服務消費端都只能通過這個關口來訪問微服務。除了作為統一入口之外,它還可以處理非業務功能,承擔認證授權、訪問控制、路由、負載均衡、日志、緩存、映射、過濾、熔斷、注冊、服務編排、API管理、監控、統計分析等職責。所以選擇一個優秀的服務網關對於開發微服務體系系統至關重要。以下是借鑒某伙伴的服務架構圖:

 

 二、Gateway的工作流程

  要理解工作流程,先了解以下三個核心名詞

    1、Route路由:路由是構建網關的基本模塊,由一系列的斷言和過濾器組成,如果斷言為true則匹配該路由。

    2、predicate斷言:預先設置的規則條件。開發人員可以匹配http請求中的內容,如果請求與斷言相匹配則進行路由匹配。

    3、Filte過濾器:過濾器是GatewayFilter的一個實例,它可以在請求被路由前后完成對請求的修改。Gateway中存在一系列過濾鏈,用於完成不同的處理(請求前可以做權限校驗、流量監控、日志輸出、協議轉換等,請求后響應內容修改等)。

  一個web請求進來,Gateway首先會進行條件匹配,定位真正的服務節點,並在轉發web請求的前后進行一些額外的處理,這些處理就通過過濾器來實現,而前面的匹配就是通過斷言來實現。以下是網關內部的工作流程圖

  三、服務網關模塊的搭建

  搭建服務網關模塊的步驟:

  1、引入jar包:除了引入gateway的jar包外,網關本身也是一種微服務,也需要注冊到服務注冊中心,因此還需要引入相應的注冊中心客戶端jar包,進行相應的配置(配置方式參考服務注冊中心相關文檔)。最后要注意的是,作為網關的模塊請不要引入

與spring-boot-starter-web相關的包,否則會出現沖突報錯。

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

   2、修改application.yml文件,配置網關路由規則。路由是多個,可以配置在routes節點下,如圖所示表示配置了兩個路由規則: 

server:
  port: 9527

spring:
  application:
     name: cloud-gateway
  cloud:
     gateway:
        routes:
           - id: payment_routh                     #路由的ID,沒有固定規則但要求唯一,建議配合服務名
             uri: http://localhost:8001            #匹配后提供服務的路由地址
             predicates:  
- Path=/payment/get/** #斷言,路徑相匹配的進行路由 - id: payment_routh2 #路由的ID,沒有固定規則但要求唯一,建議配合服務名 uri: http://localhost:8001 #匹配后提供服務的路由地址 predicates:
- Path=/payment/lb/** #斷言,路徑相匹配的進行路由

   當進行上述配置后,我們就可以不直接訪問http://localhost:8001/payment/get/來調用微服務,而是通過http://localhost:9527/payment/get/來間接調用8001微服務。當客戶端訪問http://localhost:9527/****/***時,網關服務模塊就根據路由規則進行匹配,從而調用不同的微服務(網關服務模塊獲取到請求地址后,用請求地址去斷言,斷言uri指定的微服務下是否存在predicates指定的路徑模式,如果為true則調用)。

   3、完成以上兩步,啟動網關服務模塊,客戶端向微服務的請求全部通過訪問該服務來實現,到此簡單的網關服務模塊搭建完成。

  除了2中配置文件實現路由配置的方式外,還可以通過硬編碼的方式(代碼中注入RouteLocator的Bean)來實現路由匹配:新建網關配置文件GatewayConfig類,寫入如下類似代碼即可

@Configuration
public class GatewayConfig
{ @Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder)
{ RouteLocatorBuilder.Builder routes
= routeLocatorBuilder.routes();
routes.route(
id: "path_route_name", r -> r.path("/aaaa").uri("http://xxx.com/bbbb") /* /aaaa路徑將會被路由到http://xxx.com/bbbb */
).build();
  return routes.build();
}

 四、動態路由配置

  默認情況下,Gateway會根據注冊中心注冊的服務列表,以微服務的名稱為路徑創建動態路由進行轉發,實現動態路由功能。開啟動態路由只需要在上述簡單路由的基礎上修改yml配置文件,開啟動態路由功能即可,要注意創建動態路由時uri要寫成服務名稱的形式,如下所示:

server:
  port: 9527

spring:
  application:
     name: cloud-gateway
  cloud:
     gateway:
discovery:
locator :
enabled: true #開啟從注冊中心動態創建路由的功能,利用微服務名進行路由
routes:
           - id: payment_routh                     #路由的ID,沒有固定規則但要求唯一,建議配合服務名
             uri: http://cloud-server-name         #這里寫微服務的名稱,不要用地址
             predicates:  
- Path=/payment/get/** #斷言,路徑相匹配的進行路由

 五、Gateway過濾器Filter

  過濾器允許以某種方式修改傳入的HTTP請求或返回的HTTP響應。過濾器作用於某些特定路由。Spring Cloud Gateway包括許多內置的 Filter工廠,這些工廠負責創建Filter過濾器實例,同時也支持自定義過濾器。多個過濾器結合使用可以形成過濾器鏈對http請求進行處理。

  1、內置的過濾器:分為單一過濾器GatewayFilter和全局過濾器GlobalFilter,作用於業務邏輯之前或業務邏輯之后。使用方式與斷言類似,通過配置實現過濾功能,yml配置參考代碼如下

server:
  port: 9527

spring:
  application:
     name: cloud-gateway
  cloud:
     gateway:
        discovery:
           locator :
             enabled: true 
        routes:
           - id: payment_routh                     
             uri: http://cloud-server-name         
filters:
- AddRequestParameter=X-Request-Id,1024 #過搪器工廠會在匹配的請求頭加上一對請求頭,名稱為X-Request-Id值為1024
predicates:
- Path=/payment/get/**

    2、自定義全局過濾器:新建MyGatewayFilter類,實現GlobalFilter,Orderd接口,重寫filter方法和getOrder方法,參考代碼如下

@Component
public class MyGatewayFilter implements GlobalFilter,ordered  /*實現接口*/
{
    @override
     public Mono<Void> filter(ServerwebExchange exchange,GatewayFilterchain chain) /*exchange是請求的上下文,chain表示下一過濾器*/
{
string uname = exchange.getRequest().getQueryParams( ).getFirst( key: "uname");
if(uname == nul1) { exchange.getResponse().setstatuscode(Httpstatus.NOT_ACCEPTABLE);
return exchange.getResponse().setcomplete(); /*如果uname為空,則設置狀態為不被接受,然后返回結果*/ } return chain.filter(exchange); /*繼續執行下一過濾器*/ } @Override public int getorder()
{
return 0; /*設置過濾器順序*/
}
}

   以上代碼的作用是過濾非法用戶,只需完成以上編碼,無需額外配置即可實現全局過濾功能。內置的過濾器此處不再詳述。

六、Gateway常用的斷言Predicate

  分析前面的yml配置文件,發現predicates是復數形式,表明我們可以設置多個斷言,進行更精確的匹配。Gateway提供了如下幾種斷言規則:

規則 配置格式 說明
After

- After=2020-02-05T15:10:03.685+08:00[Asia/Shanghai]

匹配在此時間之后的訪問
Before - Before=2020-02-05T15:10:03.685+08:00[Asia/Shanghai] 匹配在此時間之前的訪問
Between - Between=2020-02-05T15:10:03.685+08:00[Asia/Shanghai], 2020-02-05T15:10:03.685+08:00[Asia/Shanghai] 匹配在該時間段的訪問
Cookie - Cookie=username,zhangsan 匹配cookie名稱為zhangsan
Header - Header=X-Request-Id,\d+ 匹配請求頭要有x-Request-Id屬性並且值為整數
Host - Host=**.yy.com 匹配主機名為.yy.com
Method - Method=Get 匹配get請求
Path - Path=/payment/get/** 匹配路徑
Query - Query=username,\d+ 匹配查詢字符串存在username並且值為整數
RemoteAddr - RemoteAddr =192.168.0.1/16 匹配Remote Adress為192.168.0.1

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM