spring-cloud-gateway靜態路由

為什麼引入 API 網關

使用 API 網關後的優點如下:

  • 易於監控。可以在網關收集監控數據並將其推送到外部系統進行分析。
  • 易於認證。可以在網關上進行認證,然後再將請求轉發到後端的微服務,而無須在每個微服務中進行認證。
  • 減少了客戶端與各個微服務之間的交互次數。

基本環境見 spring-cloud-gateway 簡介, 項目中 provider1 的 maven 配置在此做下更正

pom.xml

<?xml version="1.0" encoding="UTF-8"?>  <project xmlns="http://maven.apache.org/POM/4.0.0"           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"           xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">      <parent>          <artifactId>spring-cloud-learning</artifactId>          <groupId>cn.idea360</groupId>          <version>1.0</version>      </parent>      <modelVersion>4.0.0</modelVersion>        <artifactId>idc-provider1</artifactId>        <dependencies>          <dependency>              <groupId>org.springframework.cloud</groupId>              <artifactId>spring-cloud-starter-consul-discovery</artifactId>          </dependency>            <dependency>              <groupId>org.springframework.boot</groupId>              <artifactId>spring-boot-starter-web</artifactId>          </dependency>            <dependency>              <groupId>org.springframework.boot</groupId>              <artifactId>spring-boot-starter-actuator</artifactId>          </dependency>            <dependency>              <groupId>org.springframework.cloud</groupId>              <artifactId>spring-cloud-starter-openfeign</artifactId>          </dependency>      </dependencies>      <build>          <finalName>${project.artifactId}</finalName>          <plugins>              <plugin>                  <groupId>org.springframework.boot</groupId>                  <artifactId>spring-boot-maven-plugin</artifactId>                  <version>${spring-boot.version}</version>                  <executions>                      <execution>                          <goals>                              <goal>repackage</goal>                          </goals>                      </execution>                  </executions>              </plugin>              <plugin>                  <artifactId>maven-compiler-plugin</artifactId>              </plugin>          </plugins>      </build>  </project>  

靜態路由基本實現

靜態路由比較簡單,這裡做簡單實現。

更改路由模組 application.yml 配置,更改後的配置文件如下:

server:    port: 2000  spring:    application:      name: idc-gateway    redis:      host: localhost      port: 6379      timeout: 6000ms  # 連接超時時長(毫秒)      jedis:        pool:          max-active: 1000  # 連接池最大連接數(使用負值表示沒有限制)          max-wait: -1ms      # 連接池最大阻塞等待時間(使用負值表示沒有限制)          max-idle: 10      # 連接池中的最大空閑連接          min-idle: 5       # 連接池中的最小空閑連接    cloud:      consul:        host: localhost        port: 8500      gateway:        discovery:          locator:            enabled: true # gateway可以通過開啟以下配置來打開根據服務的serviceId來匹配路由,默認是大寫        routes:          - id: provider1  # 路由 ID,保持唯一            uri: lb://idc-provider1 # uri指目標服務地址,lb代表從註冊中心獲取服務            predicates: # 路由條件。Predicate 接受一個輸入參數,返回一個布爾值結果。該介面包含多種默認方法來將 Predicate 組合成其他複雜的邏輯(比如:與,或,非)              - Path=/p/**            filters:              - StripPrefix=1 # 過濾器StripPrefix,作用是去掉請求路徑的最前面n個部分截取掉。StripPrefix=1就代表截取路徑的個數為1,比如前端過來請求/test/good/1/view,匹配成功後,路由到後端的請求路徑就會變成http://localhost:8888/good/1/view          - id: provider2  # 路由 ID,保持唯一            uri: lb://idc-provider2 # uri指目標服務地址,lb代表從註冊中心獲取服務            predicates: # 路由條件。Predicate 接受一個輸入參數,返回一個布爾值結果。該介面包含多種默認方法來將 Predicate 組合成其他複雜的邏輯(比如:與,或,非)              - Path=/p2/**            filters:              - StripPrefix=1 # 過濾器StripPrefix,作用是去掉請求路徑的最前面n個部分截取掉。StripPrefix=1就代表截取路徑的個數為1,比如前端過來請求/test/good/1/view,匹配成功後,路由到後端的請求路徑就會變成http://localhost:8888/good/1/view  

測試

執行以下請求測試路由 1

curl http://localhost:2000/p/provider1/1  

結果 返回 2001 。說明成功路由到了 provider1 服務。

執行以下請求測試路由 2

curl http://localhost:2000/p2/provider2  

返回 {"port":"2002"} 。說明成功路由到了 provider2 服務。

Predicate 斷言條件

1 通過請求參數匹配

Query Route Predicate 支援傳入兩個參數,一個是屬性名一個為屬性值,屬性值可以是正則表達式。

...          - id: provider1            uri: lb://idc-provider1            predicates:              - Path=/p/**              - Query=username            filters:              - StripPrefix=1  

這樣配置,只要請求中包含 username 屬性的參數即可匹配路由。否則 404

測試

curl http://localhost:2000/p/provider1/1?username=admin  

經過測試發現只要請求匯總帶有 username 參數即會匹配路由,不帶 username 參數則不會匹配。

還可以將 Query 的值以鍵值對的方式進行配置,這樣在請求過來時會對屬性值和正則進行匹配,匹配上才會走路由。

        - id: provider1            uri: lb://idc-provider1            predicates:              - Path=/p/**              - Query=username, ad.            filters:              - StripPrefix=1  

這樣只要當請求中包含 username 屬性並且參數值是以 admin 開頭的長度為三位的字元串才會進行匹配和路由。

測試

curl http://localhost:2000/p/provider1/1?username=adm  

測試可以返回頁面程式碼,將 username 的屬性值改為 admin 再次訪問就會報 404,證明路由需要匹配正則表達式才會進行路由。

2 通過 Header 屬性匹配

Header Route Predicate 和 Cookie Route Predicate 一樣,也是接收 2 個參數,一個 header 中屬性名稱和一個正則表達式,這個屬性值和正則表達式匹配則執行。

        - id: provider1            uri: lb://idc-provider1            predicates:              - Path=/p/**              - Header=token, d+            filters:              - StripPrefix=1  

測試

curl http://localhost:2000/p/provider1/1 -H "token:11"  

則返回頁面程式碼證明匹配成功。將參數-H "token:11"改為-H "token:spring"再次執行時返回 404 證明沒有匹配。

Cookie Route Predicate 可以接收兩個參數,一個是 Cookie name ,一個是正則表達式,路由規則會通過獲取對應的 Cookie name 值和正則表達式去匹配,如果匹配上就會執行路由,如果沒有匹配上則不執行。

        - id: provider1            uri: lb://idc-provider1            predicates:              - Path=/p/**              - Cookie=sessionId, test            filters:              - StripPrefix=1  

使用 curl 測試,命令行輸入:

curl http://localhost:2000/p/provider1/1 --cookie "sessionId=test"  

則會返回頁面程式碼,如果去掉–cookie "sessionId=test",後台會報 404 錯誤。

4 通過 Host 匹配

Host Route Predicate 接收一組參數,一組匹配的域名列表,這個模板是一個 ant 分隔的模板,用.號作為分隔符。它通過參數中的主機地址作為匹配規則。

        - id: provider1            uri: lb://idc-provider1            predicates:              - Path=/p/**              - Host=**.baidu.com            filters:              - StripPrefix=1  

使用 curl 測試,命令行輸入:

curl http://localhost:2000/p/provider1/1 -H "Host: www.baidu.com"  curl http://localhost:2000/p/provider1/1 -H "Host: md.baidu.com"  

經測試以上兩種 host 均可匹配到 host_route 路由,去掉 host 參數則會報 404 錯誤。

5 通過請求方式匹配

可以通過是 POST、GET、PUT、DELETE 等不同的請求方式來進行路由。

        - id: provider1            uri: lb://idc-provider1            predicates:              - Path=/p/**              - Method=GET            filters:              - StripPrefix=1  

使用 curl 測試,命令行輸入:

curl http://localhost:2000/p/provider1/1  

測試返回頁面程式碼,證明匹配到路由,我們再以 POST 的方式請求測試。

curl -X POST http://localhost:2000/p/provider1/1  

返回 404 沒有找到,證明沒有匹配上路由

6 通過請求路徑匹配

Path Route Predicate 接收一個匹配路徑的參數來判斷是否走路由。

        - id: provider1            uri: lb://idc-provider1            predicates:              - Path=/p/{segment}              - Method=POST            filters:              - StripPrefix=1  

如果請求路徑符合要求,則此路由將匹配,例如:/foo/1 或者 /foo/bar。

7 通過請求 ip 地址進行匹配

Predicate 也支援通過設置某個 ip 區間號段的請求才會路由,RemoteAddr Route Predicate 接受 cidr 符號(IPv4 或 IPv6 )字元串的列表(最小大小為 1),例如 192.168.124.5/16 (其中 192.168.124.5 是 IP 地址,16 是子網掩碼)。

        - id: provider1            uri: lb://idc-provider1            predicates:              - Path=/p/**              - RemoteAddr=192.168.124.5/16            filters:              - StripPrefix=1  

可以將此地址設置為本機的 ip 地址進行測試。

curl http://192.168.124.5:2000/p/provider1/1  

如果請求的遠程地址是 192.168.124.5,則此路由將匹配。

8 組合使用

各種 Predicates 同時存在於同一個路由時,請求必須同時滿足所有的條件才被這個路由匹配。

一個請求滿足多個路由的斷言條件時,請求只會被首個成功匹配的路由轉發

結語

本篇到此結束,歡迎大家關注公眾號【當我遇上你】。