1. 程式人生 > >熬夜肝了這篇Spring Cloud Gateway的功能及綜合使用

熬夜肝了這篇Spring Cloud Gateway的功能及綜合使用

## 前言 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