熬夜肝了這篇Spring Cloud Gateway的功能及綜合使用
阿新 • • 發佈:2020-12-27
## 前言
SpringCloud 是微服務中的翹楚,最佳的落地方案。
Spring Cloud Gateway 是 Spring Cloud 新推出的閘道器框架,之前是 Netflix Zuul。閘道器通常在專案中為了簡化
前端的呼叫邏輯,同時也簡化內部服務之間互相呼叫的複雜度;具體作用就是轉發服務,接收並轉發所有內外
部的客戶端呼叫;其他常見的功能還有許可權認證,限流控制等等。
本部落格會提到閘道器的基本**轉發功能**,**熔斷功能**,**限流功能**以及功能的**綜合使用**。
## 原始碼
GitHub地址:https://github.com/intomylife/SpringCloud
## 環境
JDK 1.8.0 +
Maven 3.0 +
SpringBoot 2.0.3
SpringCloud Finchley.RELEASE
Redis 3.0 +
## 開發工具
IntelliJ IDEA
## 正文
## commons 工程
## commons 工程 - POM 檔案
```
```
配置一些共用依賴
## commons 工程 - 專案結構
![](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/bf4843a0eb904c28b5c34a85d033b527~tplv-k3u1fbpfcp-watermark.image)
## service 工程
**① 此工程下有四個模組:一個註冊中心,一個閘道器以及兩個提供者
**② 兩個提供者除埠不一致以外,其他程式碼基本一致**
## registry-service(註冊中心)
## registry-service - POM 檔案
```
```
主要加入 spring-cloud-starter-netflix-eureka-server 依賴
## registry-service - application.yml 配置檔案
```
#埠
server:
port: 8761
#應用名稱
spring:
application:
name: eureka-server
eureka:
instance:
# 使用 ip 代替例項名
prefer-ip-address: true
# 例項的主機名
hostname: ${spring.cloud.client.ip-address}
# 例項的 ID 規則
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
client:
# 是否向註冊中心註冊自己
registerWithEureka: false
# 是否向註冊中心獲取註冊資訊
fetchRegistry: false
serviceUrl:
# 註冊中心地址
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
```
這裡使用了預設的 8761 埠,當然也可以更改,不過在發現呼叫服務端的註冊中心地址埠要與它一致
## registry-service - 啟動類
```
package com.zwc;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class SpringcloudGatewayRegistryServiceApplication {
public static void main(String[] args) {
SpringApplication.run(SpringcloudGatewayRegistryServiceApplication.class, args);
}
}
```
在啟動類中新增 @EnableEurekaServer 註解表示此工程是註冊中心
## registry-service - 啟動專案
1. 專案啟動成功後訪問 http://localhost:8761/ 即可看到 eureka-server 主頁面
![](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7c0f308d94e74ec18eadabb4a6976c49~tplv-k3u1fbpfcp-watermark.image)
**注:由於服務工程 A 和服務工程 B 除埠不一致以外,其他程式碼基本一致,所以服務工程 B 不再贅述**
## a-service(服務工程 A)
## a-service - POM 檔案
```
```
**加入spring-cloud-starter-netflix-eureka-client依賴**
## a-service - application.yml 配置檔案
```
#埠
server:
port: 9000
#應用名稱
spring:
application:
name: gateway-service
eureka:
instance:
# 使用 ip 代替例項名
prefer-ip-address: true
# 例項的主機名
hostname: ${spring.cloud.client.ip-address}
# 例項的 ID 規則
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
client:
serviceUrl:
# 註冊中心地址
defaultZone: http://${eureka.instance.hostname}:8761/eureka/
```
**注意此處配置註冊中心地址的埠為 8761 也就是上面註冊中心工程配置的埠**
## a-service - controller 前端控制器(提供服務)
```
package com.zwc.a.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/*
* @ClassName ASayHelloController
* @Desc TODO Say Hello
* @Date 2019/5/20 23:24
* @Version 1.0
*/
@RestController
public class ASayHelloController {
/*
* @ClassName ASayHelloController
* @Desc TODO 讀取配置檔案中的埠
* @Date 2019/5/20 23:24
* @Version 1.0
*/
@Value("${server.port}")
private String port;
/*
* @ClassName ASayHelloController
* @Desc TODO Say Hello
* @Date 2019/5/20 23:24
* @Version 1.0
*/
@RequestMapping("/hello")
public String hello(){
return "Hello!I'm a. port:" + port;
}
/*
* @ClassName ASayHelloController
* @Desc TODO 接收從閘道器傳入的引數
* @Date 2019/6/23 16:28
* @Version 1.0
*/
@RequestMapping("/name")
public String name(String name){
return "My name is " + name + ". aaa";
}
/*
* @ClassName ASayHelloController
* @Desc TODO 接收從閘道器傳入的引數
* @Date 2019/6/23 16:52
* @Version 1.0
*/
@RequestMapping("/age")
public String age(String age){
return "I am " + age + " years old this year. aaa";
}
/*
* @ClassName ASayHelloController
* @Desc TODO 接收從閘道器傳入的引數
* @Date 2019/6/29 22:00
* @Version 1.0
*/
@RequestMapping("/routeAll")
public String routeAll(String pass) {
return "Can I pass? " + pass + "! port:" + port;
}
}
```
提供輸出字串服務,供閘道器呼叫
## a-service - 啟動類
```
package com.zwc;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class SpringcloudGatewayAServiceCoreApplication {
public static void main(String[] args) {
SpringApplication.run(SpringcloudGatewayAServiceCoreApplication.class, args);
}
}
```
新增 @EnableEurekaClient 註解表示此工程可以向註冊中心提供服務
## a-service - 啟動專案
1. 重新整理 http://localhost:8761/(註冊中心)可以看到服務已經被註冊進來了
![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/562a7ccfda5f4cd3a3fec36265c1c2bd~tplv-k3u1fbpfcp-watermark.image)
2. 專案啟動成功後訪問:http://localhost:9000/hello
3. 輸出內容:'Hello!I'm a. port:9000'
4. 同樣啟動服務工程 B後,重新整理 http://localhost:8761/(註冊中心)
![](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/635b96ea7cb64f93b6bbe185466d2b7b~tplv-k3u1fbpfcp-watermark.image)
5. 專案啟動成功後訪問:http://localhost:9001/hello
6. 輸出內容:'Hello!I'm b. port:9001'
7. 其他介面是下面閘道器服務啟動後轉發呼叫的,也是本部落格的重頭戲
## master-service(閘道器)
## master-service - POM 檔案
```
```
加入spring-cloud-starter-netflix-eureka-client 依賴:提供和註冊服務
加入spring-cloud-starter-gateway 依賴:gateway
加入spring-boot-starter-data-redis-reactive 依賴:結合 Redis 限流
加入spring-cloud-starter-netflix-hystrix 依賴:熔斷器
## master-service - application.yml 配置檔案
```
#埠
server:
port: 8000
spring:
profiles:
# 指定配置
# route_simple:簡單嘗試
# route_stripPrefix:擷取請求
# route_uri:轉發指定地址並傳入引數
# route_addRequestParameter:轉發指定服務並傳入引數
# route_hystrix:熔斷
# route_requestRateLimiter:限流
# route_all:綜合
active: route_simple
---
spring:
# 配置檔名稱,用來標識不同環境的配置。由 spring.profiles.active 的值來決定使用哪組配置。
## 簡單嘗試
profiles: route_simple
application:
# 應用名稱
name: gateway-master
cloud:
gateway:
discovery:
locator:
# 是否和服務註冊與發現元件結合,設定為 true 後可以直接使用應用名稱呼叫服務
enabled: true
# 路由(routes:路由,它由唯一標識(ID)、目標服務地址(uri)、一組斷言(predicates)和一組過濾器組成(filters)。filters 不是必需引數。)
routes:
# 路由標識(id:標識,具有唯一性) 簡單嘗試
- id: route_simple
# 目標服務地址(uri:地址,請求轉發後的地址)
uri: https://www.zouwencong.com
# 路由條件(predicates:斷言,匹配 HTTP 請求內容)
predicates:
## 轉發地址格式為 uri/archive
- Path=/archive
eureka:
instance:
# 使用 ip 代替例項名
prefer-ip-address: true
# 例項的主機名
hostname: ${spring.cloud.client.ip-address}
# 例項的 ID 規則
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
client:
serviceUrl:
# 註冊中心地址
defaultZone: http://${eureka.instance.hostname}:8761/eureka/
logging:
level:
# log 級別
org.springframework.cloud.gateway: debug
---
spring:
# 配置檔名稱,用來標識不同環境的配置。由 spring.profiles.active 的值來決定使用哪組配置。
## 擷取請求
profiles: route_stripPrefix
application:
# 應用名稱
name: gateway-master
cloud:
gateway:
discovery:
locator:
# 是否和服務註冊與發現元件結合,設定為 true 後可以直接使用應用名稱呼叫服務
enabled: true
# 路由(routes:路由,它由唯一標識(ID)、目標服務地址(uri)、一組斷言(predicates)和一組過濾器組成(filters)。filters 不是必需引數。)
routes:
# 路由標識(id:標識,具有唯一性) 擷取請求
- id: route_simple
# 目標服務地址(uri:地址,請求轉發後的地址)
uri: https://www.zouwencong.com
# 路由條件(predicates:斷言,匹配 HTTP 請求內容)
predicates:
## 轉發地址格式為 uri/archive,/str 部分會被下面的過濾器給擷取掉
- Path=/str/archive
filters:
## 擷取路徑位數
- StripPrefix=1
eureka:
instance:
# 使用 ip 代替例項名
prefer-ip-address: true
# 例項的主機名
hostname: ${spring.cloud.client.ip-address}
# 例項的 ID 規則
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
client:
serviceUrl:
# 註冊中心地址
defaultZone: http://${eureka.instance.hostname}:8761/eureka/
logging:
level:
# log 級別
org.springframework.cloud.gateway: debug
---
spring:
# 配置檔名稱,用來標識不同環境的配置。由 spring.profiles.active 的值來決定使用哪組配置。
## 轉發指定地址並傳入引數
profiles: route_uri
application:
# 應用名稱
name: gateway-master
cloud:
gateway:
discovery:
locator:
# 是否和服務註冊與發現元件結合,設定為 true 後可以直接使用應用名稱呼叫服務
enabled: true
# 路由(routes:路由,它由唯一標識(ID)、目標服務地址(uri)、一組斷言(predicates)和一組過濾器組成(filters)。filters 不是必需引數。)
routes:
# 路由標識(id:標識,具有唯一性) 轉發指定地址並傳入引數
- id: route_uri
# 目標服務地址(uri:地址,請求轉發後的地址)
uri: http://localhost:9000
# 路由條件(predicates:斷言,匹配 HTTP 請求內容)
predicates:
## 匹配 GET 請求
- Method=GET
# 過濾器(filters:過濾器,過濾規則)
filters:
## 新增指定引數
- AddRequestParameter=name, zwc
eureka:
instance:
# 使用 ip 代替例項名
prefer-ip-address: true
# 例項的主機名
hostname: ${spring.cloud.client.ip-address}
# 例項的 ID 規則
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
client:
serviceUrl:
# 註冊中心地址
defaultZone: http://${eureka.instance.hostname}:8761/eureka/
logging:
level:
# log 級別
org.springframework.cloud.gateway: debug
---
spring:
# 配置檔名稱,用來標識不同環境的配置。由 spring.profiles.active 的值來決定使用哪組配置。
## 轉發指定服務並傳入引數
profiles: route_addRequestParameter
application:
# 應用名稱
name: gateway-master
cloud:
gateway:
discovery:
locator:
# 是否和服務註冊與發現元件結合,設定為 true 後可以直接使用應用名稱呼叫服務
enabled: true
# 路由(routes:路由,它由唯一標識(ID)、目標服務地址(uri)、一組斷言(predicates)和一組過濾器組成(filters)。filters 不是必需引數。)
routes:
# 路由標識(id:標識,具有唯一性) 轉發指定服務並傳入引數
- id: route_addRequestParameter
# 目標服務地址(uri:地址,請求轉發後的地址)
uri: lb://gateway-service
# 路由條件(predicates:斷言,匹配 HTTP 請求內容)
predicates:
## 匹配 GET 請求
- Method=GET
# 過濾器(filters:過濾器,過濾規則)
filters:
## 新增指定引數
- AddRequestParameter=age, three
eureka:
instance:
# 使用 ip 代替例項名
prefer-ip-address: true
# 例項的主機名
hostname: ${spring.cloud.client.ip-address}
# 例項的 ID 規則
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
client:
serviceUrl:
# 註冊中心地址
defaultZone: http://${eureka.instance.hostname}:8761/eureka/
logging:
level:
# log 級別
org.springframework.cloud.gateway: debug
---
spring:
# 配置檔名稱,用來標識不同環境的配置。由 spring.profiles.active 的值來決定使用哪組配置。
## 熔斷
profiles: route_hystrix
application:
# 應用名稱
name: gateway-master
cloud:
gateway:
discovery:
locator:
# 是否和服務註冊與發現元件結合,設定為 true 後可以直接使用應用名稱呼叫服務
enabled: true
# 路由(routes:路由,它由唯一標識(ID)、目標服務地址(uri)、一組斷言(predicates)和一組過濾器組成(filters)。filters 不是必需引數。)
routes:
# 路由標識(id:標識,具有唯一性) 熔斷
- id: route_hystrix
# 目標服務地址(uri:地址,請求轉發後的地址)
uri: lb://gateway-service
# 路由條件(predicates:斷言,匹配 HTTP 請求內容)
predicates:
## 匹配 GET 請求
- Method=GET
# 過濾器(filters:過濾器,過濾規則)
filters:
## 新增指定引數
- AddRequestParameter=age, three
## 熔斷
- name: Hystrix
args:
name: fallbackcmd
### fallback 時呼叫的方法 http://localhost:8000/fallback
fallbackUri: forward:/fallback
eureka:
instance:
# 使用 ip 代替例項名
prefer-ip-address: true
# 例項的主機名
hostname: ${spring.cloud.client.ip-address}
# 例項的 ID 規則
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
client:
serviceUrl:
# 註冊中心地址
defaultZone: http://${eureka.instance.hostname}:8761/eureka/
logging:
level:
# log 級別
org.springframework.cloud.gateway: debug
---
spring:
# 配置檔名稱,用來標識不同環境的配置。由 spring.profiles.active 的值來決定使用哪組配置。
## 限流
profiles: route_requestRateLimiter
redis:
host: localhost
port: 6379
database: 0
application:
# 應用名稱
name: gateway-master
cloud:
gateway:
discovery:
locator:
# 是否和服務註冊與發現元件結合,設定為 true 後可以直接使用應用名稱呼叫服務
enabled: true
# 路由(routes:路由,它由唯一標識(ID)、目標服務地址(uri)、一組斷言(predicates)和一組過濾器組成(filters)。filters 不是必需引數。)
routes:
# 路由標識(id:標識,具有唯一性) 限流
- id: route_requestRateLimiter
# 目標服務地址(uri:地址,請求轉發後的地址)
uri: lb://gateway-service
# 路由條件(predicates:斷言,匹配 HTTP 請求內容)
predicates:
## 匹配 GET 請求
- Method=GET
# 過濾器(filters:過濾器,過濾規則)
filters:
## 新增指定引數
- AddRequestParameter=age, three
## 限流
- name: RequestRateLimiter
args:
### 限流過濾器的 Bean 名稱
key-resolver: '#{@uriKeyResolver}'
### 希望允許使用者每秒處理多少個請求
redis-rate-limiter.replenishRate: 1
### 使用者允許在一秒鐘內完成的最大請求數
redis-rate-limiter.burstCapacity: 3
eureka:
instance:
# 使用 ip 代替例項名
prefer-ip-address: true
# 例項的主機名
hostname: ${spring.cloud.client.ip-address}
# 例項的 ID 規則
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
client:
serviceUrl:
# 註冊中心地址
defaultZone: http://${eureka.instance.hostname}:8761/eureka/
logging:
level:
# log 級別
org.springframework.cloud.gateway: debug
---
spring:
# 配置檔名稱,用來標識不同環境的配置。由 spring.profiles.active 的值來決定使用哪組配置。
## 綜合
profiles: route_all
redis:
host: localhost
port: 6379
database: 0
application:
# 應用名稱
name: gateway-master
cloud:
gateway:
discovery:
locator:
# 是否和服務註冊與發現元件結合,設定為 true 後可以直接使用應用名稱呼叫服務
enabled: true
# 路由(routes:路由,它由唯一標識(ID)、目標服務地址(uri)、一組斷言(predicates)和一組過濾器組成(filters)。filters 不是必需引數。)
routes:
# 路由標識(id:標識,具有唯一性) 綜合
- id: route_all
# 目標服務地址(uri:地址,請求轉發後的地址)
uri: lb://gateway-service
# 路由條件(predicates:斷言,匹配 HTTP 請求內容)
predicates:
## 轉發地址格式為 uri/routeAll,/all 部分會被下面的過濾器給擷取掉
- Path=/all/routeAll
## 匹配 GET 請求
- Method=GET
# 過濾器(filters:過濾器,過濾規則)
filters:
## 擷取路徑位數
- StripPrefix=1
## 新增指定引數
- AddRequestParameter=pass, yes
## 熔斷
- name: Hystrix
args:
name: fallbackcmd
### fallback 時呼叫的方法 http://localhost:8000/fallback
fallbackUri: forward:/fallback
## 限流
- name: RequestRateLimiter
args:
### 限流過濾器的 Bean 名稱
key-resolver: '#{@uriKeyResolver}'
### 希望允許使用者每秒處理多少個請求
redis-rate-limiter.replenishRate: 1
### 使用者允許在一秒鐘內完成的最大請求數
redis-rate-limiter.burstCapacity: 3
eureka:
instance:
# 使用 ip 代替例項名
prefer-ip-address: true
# 例項的主機名
hostname: ${spring.cloud.client.ip-address}
# 例項的 ID 規則
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
client:
serviceUrl:
# 註冊中心地址
defaultZone: http://${eureka.instance.hostname}:8761/eureka/
logging:
level:
# log 級別
org.springframework.cloud.gateway: debug
```
**注意配置註冊中心地址的埠都為 8761 也就是上面註冊中心工程配置的埠**
每一對 '---' 符號中的配置檔案都是單獨的,使用 spring.profiles.active 指定
每一對 '---' 符號中的配置檔案都只配置了一個 route(路由)
route(路由)由四部分組成,其中 filters 不是必須引數
唯一標識(ID)、目標服務地址(uri)、一組斷言(predicates)和一組過濾器組成(filters)
## master-service - 簡單嘗試
```
spring:
# 配置檔名稱,用來標識不同環境的配置。由 spring.profiles.active 的值來決定使用哪組配置。
## 簡單嘗試
profiles: route_simple
application:
# 應用名稱
name: gateway-master
cloud:
gateway:
discovery:
locator:
# 是否和服務註冊與發現元件結合,設定為 true 後可以直接使用應用名稱呼叫服務
enabled: true
# 路由(routes:路由,它由唯一標識(ID)、目標服務地址(uri)、一組斷言(predicates)和一組過濾器組成(filters)。filters 不是必需引數。)
routes:
# 路由標識(id:標識,具有唯一性) 簡單嘗試
- id: route_simple
# 目標服務地址(uri:地址,請求轉發後的地址)
uri: https://www.zouwencong.com
# 路由條件(predicates:斷言,匹配 HTTP 請求內容)
predicates:
## 轉發地址格式為 uri/archive
- Path=/archive
```
1. 停止註冊中心工程(registry-service)、服務工程 A 和服務工程 B
2. 把 master-service - application.yml 配置檔案中最上面的 spring.profiles.active 的值更改為 route_simple
3. 上面配置檔案內容意思是當訪問 http://localhost:8000/archive (閘道器地址/archive)
會被轉發到 https://www.zouwencong.com/archive/ (uri/archive)
4. 啟動註冊中心工程(registry-service)和閘道器工程(master-service)
5. 專案啟動成功後訪問:http://localhost:8000/archive
6. 發現頁面會自動被跳轉到:https://www.zouwencong.com/archive/
7. 證明服務轉發成功
## master-service - 擷取請求
```
spring:
#配置檔名稱,用來標識不同環境的配置。由 spring.profiles.active 的值來決定使用哪組配置。
##擷取請求
profiles: route_stripPrefix
application:
# 應用名稱
name: gateway-master
cloud:
gateway:
discovery:
locator:
# 是否和服務註冊與發現元件結合,設定為 true 後可以直接使用應用名稱呼叫服務
enabled: true
# 路由(routes:路由,它由唯一標識(ID)、目標服務地址(uri)、一組斷言(predicates)和一組過濾器組成(filters)。filters 不是必需引數。)
routes:
# 路由標識(id:標識,具有唯一性) 擷取請求
- id: route_simple
# 目標服務地址(uri:地址,請求轉發後的地址)
uri: https://www.zouwencong.com
# 路由條件(predicates:斷言,匹配 HTTP 請求內容)
predicates:
## 轉發地址格式為 uri/archive,/str 部分會被下面的過濾器給擷取掉
- Path=/str/archive
filters:
## 擷取路徑位數
- StripPrefix=1
eureka:
instance:
# 使用 ip 代替例項名
prefer-ip-address: true
# 例項的主機名
hostname: ${spring.cloud.client.ip-address}
# 例項的 ID 規則
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
client:
serviceUrl:
# 註冊中心地址
defaultZone: http://${eureka.instance.hostname}:8761/eureka/
logging:
level:
# log 級別
org.springframework.cloud.gateway: debug
```
1. 停止註冊中心工程(registry-service)和閘道器工程(master-service)
2. 把 master-service - application.yml 配置檔案中最上面的 spring.profiles.active 的值更改為 route_stripPrefix
3. 上面配置檔案內容意思是訪問的路徑 http://localhost:8000/str/archive (閘道器地址/str/archive)擷取 /str 部分,
擷取後被轉發到 https://www.zouwencong.com/archive/ (uri/archive)
4. 啟動註冊中心工程(registry-service)和閘道器工程(master-service)
5. 專案啟動成功後訪問:http://localhost:8000/str/archive
6. 發現頁面會自動被跳轉到:https://www.zouwencong.com/archive/
7. 證明路徑被擷取並服務轉發成功
## master-service - 轉發指定地址並傳入引數
```
spring:
#配置檔名稱,用來標識不同環境的配置。由 spring.profiles.active 的值來決定使用哪組配置。
##轉發指定地址並傳入引數
profiles: route_uri
application:
# 應用名稱
name: gateway-master
cloud:
gateway:
discovery:
locator:
# 是否和服務註冊與發現元件結合,設定為 true 後可以直接使用應用名稱呼叫服務
enabled: true
# 路由(routes:路由,它由唯一標識(ID)、目標服務地址(uri)、一組斷言(predicates)和一組過濾器組成(filters)。filters 不是必需引數。)
routes:
# 路由標識(id:標識,具有唯一性) 轉發指定地址並傳入引數
- id: route_uri
# 目標服務地址(uri:地址,請求轉發後的地址)
uri: http://localhost:9000
# 路由條件(predicates:斷言,匹配 HTTP 請求內容)
predicates:
## 匹配 GET 請求
- Method=GET
# 過濾器(filters:過濾器,過濾規則)
filters:
## 新增指定引數
- AddRequestParameter=name, zwc
eureka:
instance:
# 使用 ip 代替例項名
prefer-ip-address: true
# 例項的主機名
hostname: ${spring.cloud.client.ip-address}
# 例項的 ID 規則
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
client:
serviceUrl:
# 註冊中心地址
defaultZone: http://${eureka.instance.hostname}:8761/eureka/
logging:
level:
# log 級別
org.springframework.cloud.gateway: debug
```
1. 停止註冊中心工程(registry-service)和閘道器工程(master-service)
2. 把 master-service - application.yml 配置檔案中最上面的 spring.profiles.active 的值更改為 route_uri
3. 上面配置檔案內容意思是訪問的路徑 http://localhost:8000/name (閘道器地址/name)
會被轉發到 http://localhost:9000/name(uri/name),並傳入 'name=zwc' 引數(注意為 Get 請求)
4. 啟動註冊中心工程(registry-service),閘道器工程(master-service)和服務工程 A(a-service)
5. 專案啟動成功後訪問:http://localhost:8000/name
6. 輸出內容:'My name is zwc. aaa'(通過閘道器轉發 - 引數有值)
7. 開啟新頁面訪問:http://localhost:9000/name
8. 輸出內容:'My name is null. aaa'(直接訪問 - 引數沒有值)
9. 證明轉發指定地址並傳入引數成功
## master-service - 轉發指定服務並傳入引數
```
spring:
#配置檔名稱,用來標識不同環境的配置。由 spring.profiles.active 的值來決定使用哪組配置。
##轉發指定服務並傳入引數
profiles: route_addRequestParameter
application:
# 應用名稱
name: gateway-master
cloud:
gateway:
discovery:
locator:
# 是否和服務註冊與發現元件結合,設定為 true 後可以直接使用應用名稱呼叫服務
enabled: true
# 路由(routes:路由,它由唯一標識(ID)、目標服務地址(uri)、一組斷言(predicates)和一組過濾器組成(filters)。filters 不是必需引數。)
routes:
# 路由標識(id:標識,具有唯一性) 轉發指定服務並傳入引數
- id: route_addRequestParameter
# 目標服務地址(uri:地址,請求轉發後的地址)
uri: lb://gateway-service
# 路由條件(predicates:斷言,匹配 HTTP 請求內容)
predicates:
## 匹配 GET 請求
- Method=GET
# 過濾器(filters:過濾器,過濾規則)
filters:
## 新增指定引數
- AddRequestParameter=age, three
eureka:
instance:
# 使用 ip 代替例項名
prefer-ip-address: true
# 例項的主機名
hostname: ${spring.cloud.client.ip-address}
# 例項的 ID 規則
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
client:
serviceUrl:
# 註冊中心地址
defaultZone: http://${eureka.instance.hostname}:8761/eureka/
logging:
level:
# log 級別
org.springframework.cloud.gateway: debug
```
1. 停止註冊中心工程(registry-service),閘道器工程(master-service)和服務工程 A(a-service)
2. 把 master-service - application.yml 配置檔案中最上面的 spring.profiles.active 的值更改為 route_addRequestParameter
3. 上面配置檔案內容意思是訪問的路徑 http://localhost:8000/age (閘道器地址/age)會被轉發到 http://gateway-service/age(uri/age),並傳入 'age=three' 引數(注意為 Get 請求)
4. 注意此處的配置 uri: lb://gateway-service 與之前都有所不同,之前都是指定了明確的轉發地址,可以滿足單個服務轉發的需求,但是一般情況都會有多個服務,所以這裡是指定的服務名稱,格式為:lb://應用註冊服務名。
5. 啟動註冊中心工程(registry-service),閘道器工程(master-service)和服務工程 A/B(a-service、b-service)
6. 專案啟動成功後訪問:http://localhost:8000/age
7. 這時可能會報錯 500.錯誤資訊為 'Unable to find instance for gateway-service'
8. 這種情況不要慌張,只是服務還沒有被註冊到註冊中心,稍等片刻再訪問
9. 多次訪問:http://localhost:8000/age
10. 輪流輸出內容:'I am three years old this year. aaa' 和 'I am three years old this year. bbb'
11. 此時還通過閘道器達到了負載均衡的效果
12. 證明轉發指定服務並傳入引數成功
## master-service - 熔斷
```
spring:
#配置檔名稱,用來標識不同環境的配置。由 spring.profiles.active 的值來決定使用哪組配置。
##熔斷
profiles: route_hystrix
application:
# 應用名稱
name: gateway-master
cloud:
gateway:
discovery:
locator:
# 是否和服務註冊與發現元件結合,設定為 true 後可以直接使用應用名稱呼叫服務
enabled: true
# 路由(routes:路由,它由唯一標識(ID)、目標服務地址(uri)、一組斷言(predicates)和一組過濾器組成(filters)。filters 不是必需引數。)
routes:
# 路由標識(id:標識,具有唯一性) 熔斷
- id: route_hystrix
# 目標服務地址(uri:地址,請求轉發後的地址)
uri: lb://gateway-service
# 路由條件(predicates:斷言,匹配 HTTP 請求內容)
predicates:
## 匹配 GET 請求
- Method=GET
# 過濾器(filters:過濾器,過濾規則)
filters:
## 新增指定引數
- AddRequestParameter=age, three
## 熔斷
- name: Hystrix
args:
name: fallbackcmd
### fallback 時呼叫的方法 http://localhost:8000/fallback
fallbackUri: forward:/fallback
eureka:
instance:
# 使用 ip 代替例項名
prefer-ip-address: true
# 例項的主機名
hostname: ${spring.cloud.client.ip-address}
# 例項的 ID 規則
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
client:
serviceUrl:
# 註冊中心地址
defaultZone: http://${eureka.instance.hostname}:8761/eureka/
logging:
level:
# log 級別
org.springframework.cloud.gateway: debug
```
1. 停止註冊中心工程(registry-service),閘道器工程(master-service)和服務工程 A/B(a-service、b-service)
2. 把 master-service - application.yml 配置檔案中最上面的 spring.profiles.active 的值更改為 route_hystrix
3. 上面配置檔案內容意思是訪問的路徑 http://localhost:8000/age (閘道器地址/age)會被轉發到 http://gateway-service/age(uri/age),並傳入 'age=three' 引數(注意為 Get 請求)
4. 注意此處的配置 uri: lb://gateway-service 與之前都有所不同,之前都是指定了明確的轉發地址,可以滿足單個服務轉發的需求,但是一般情況都會有多個服務,所以這裡是指定的服務名稱,格式為:lb://應用註冊服務名。
5. 此處還多配置了一個過濾器 '- name: Hystrix'(熔斷)
6. 當請求服務出錯時,會呼叫 fallback,路徑為:http://localhost:8000/fallback (閘道器地址/fallback)
7. 此時就需要如下前端控制器
## master-service - 熔斷 - controller
```
package com.zwc.gateway.hystrix;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @ClassName FallbackController
* @Desc TODO 閘道器斷路器
* @Date 2019/6/23 19:33
* @Version 1.0
*/
@RestController
public class FallbackController {
/*
* @ClassName FallbackController
* @Desc TODO 閘道器斷路器
* @Date 2019/6/23 19:35
* @Version 1.0
*/
@RequestMapping("/fallback")
public String fallback() {
return "I'm Spring Cloud Gateway fallback.";
}
```
}
8. 啟動註冊中心工程(registry-service),閘道器工程(master-service)和服務工程 A/B(a-service、b-service)
9. 專案啟動成功後訪問:http://localhost:8000/age
10. 輸出內容:'I'm Spring Cloud Gateway fallback.'
11. 證明熔斷成功
## master-service - 限流(重點,解決不生效問題)
```
spring:
#配置檔名稱,用來標識不同環境的配置。由 spring.profiles.active 的值來決定使用哪組配置。
##限流
profiles: route_requestRateLimiter
redis:
host: localhost
port: 6379
database: 0
application:
# 應用名稱
name: gateway-master
cloud:
gateway:
discovery:
locator:
# 是否和服務註冊與發現元件結合,設定為 true 後可以直接使用應用名稱呼叫服務
enabled: true
# 路由(routes:路由,它由唯一標識(ID)、目標服務地址(uri)、一組斷言(predicates)和一組過濾器組成(filters)。filters 不是必需引數。)
routes:
# 路由標識(id:標識,具有唯一性) 限流
- id: route_requestRateLimiter
# 目標服務地址(uri:地址,請求轉發後的地址)
uri: lb://gateway-service
# 路由條件(predicates:斷言,匹配 HTTP 請求內容)
predicates:
## 匹配 GET 請求
- Method=GET
# 過濾器(filters:過濾器,過濾規則)
filters:
## 新增指定引數
- AddRequestParameter=age, three
## 限流
- name: RequestRateLimiter
args:
### 限流過濾器的 Bean 名稱
key-resolver: '#{@uriKeyResolver}'
### 希望允許使用者每秒處理多少個請求
redis-rate-limiter.replenishRate: 1
### 使用者允許在一秒鐘內完成的最大請求數
redis-rate-limiter.burstCapacity: 3
eureka:
instance:
# 使用 ip 代替例項名
prefer-ip-address: true
# 例項的主機名
hostname: ${spring.cloud.client.ip-address}
# 例項的 ID 規則
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
client:
serviceUrl:
# 註冊中心地址
defaultZone: http://${eureka.instance.hostname}:8761/eureka/
logging:
level:
# log 級別
org.springframework.cloud.gateway: debug
```
1. 停止註冊中心工程(registry-service),閘道器工程(master-service)和服務工程 A/B(a-service、b-service)
2. 把 master-service - application.yml 配置檔案中最上面的 spring.profiles.active 的值更改route_requestRateLimiter
3. 上面配置檔案內容意思是訪問的路徑 http://localhost:8000/age (閘道器地址/age)會被轉發到 http://gateway-service/age(uri/age),並傳入 'age=three' 引數(注意為 Get 請求)
4. 注意此處還需要配置 redis 的連線資訊
5. 注意此處是結合 redis 實現的限流,所以 filter 過濾器的 name 必須為 RequestRateLimiter
6. 並且通過實現 KeyResolver 類來自定義限流策略,如下
## master-service - 限流 - 策略
```
package com.zwc.gateway.config.filters;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* @ClassName UriKeyResolver
* @Desc TODO Spring Cloud Gateway 閘道器限流過濾器
* @Date 2019/6/23 17:59
* @Version 1.0
*/
public class UriKeyResolver implements KeyResolver {
/*
* @ClassName UriKeyResolver
* @Desc TODO 根據請求的 uri 限流
* @Date 2019/6/29 17:25
* @Version 1.0
*/
@Override
pub