目錄
- 第一章 Gateway介紹
- 1.1、什么是Gateway
- 1.2、為啥用Gateway
- 第二章 Gateway三大核心
- 第三章 Gateway作業流程
- 第四章 Gateway路由功能
- 4.1、專案準備與啟動
- 4.2、工程搭建與測驗
- 4.3、配置自定義路由
- 4.4、禁止默認的路由
- 4.5、配置動態的路由
- 4.6、用代碼來配路由
- 4.7、為下章節做準備
- 第五章 Gateway斷言功能
- 5.1、謂詞:Path
- 5.2、謂詞:After
- 5.3、謂詞:Before
- 5.4、謂詞:Between
- 5.5、謂詞:Cookie
- 5.6、謂詞:Header
- 5.7、謂詞:Host
- 5.8、謂詞:Method
- 5.9、謂詞:Query
- 5.10、謂詞:RemoteAddr
- 5.11、謂詞:Weight
- 第六章 Gateway過濾功能
- 6.1、內置的網關過濾器
- 6.1.1、RewritePath
- 6.1.2、StripPrefix
- 6.1.3、PrefixPath
- 6.1.4、SetPath
- 6.1.5、SetStatus
- 6.1.6、AddRequestParameter
- 6.1.7、AddRequestHeader
- 6.1.8、AddResponseHeader
- 6.2、內置的全域過濾器
- 6.3、自定義網關過濾器
- 6.3.1、創建過濾器
- 6.3.2、注冊過濾器
- 6.3.3、測驗過濾器
- 6.4、自定義全域過濾器
- 6.4.1、創建過濾器
- 6.4.2、注冊過濾器
- 6.4.3、測驗過濾器
- 第七章 Gateway熔斷降級
- 7.1、熔斷降級含義
- 7.2、添加依賴檔案
- 7.3、撰寫組態檔
- 7.4、撰寫降級方法
- 7.5、網關熔斷測驗
- 7.6、網關降級測驗
- 第八章 Gateway網關限流
- 8.1、網關限流含義
- 8.2、網關限流演算法
- 8.3、添加依賴檔案
- 8.4、撰寫組態檔
- 8.5、啟動redis應用
- 8.6、網關限流測驗
- 第九章 Gateway跨域問題
- 第十章 Gateway統一鑒權
配套資料,免費下載
鏈接:https://pan.baidu.com/s/1la_3-HW-UvliDRJzfBcP_w
提取碼:lxfx
復制這段內容后打開百度網盤手機App,操作更方便哦
第一章 Gateway介紹
1.1、什么是Gateway
Spring Cloud Gateway是Spring官方基于Spring 5.0,Spring Boot 2.0和Project Reactor等技術開發的網關,Spring Cloud Gateway旨在為微服務架構提供一種簡單而有效的統一的API路由管理方式,Spring Cloud Gateway作為Spring Cloud生態系中的網關,目標是替代Zuul,其不僅提供統一的路由方式,并且基于Filter鏈的方式提供了網關基本的功能,例如:安全鑒權、指標監控以及熔斷限流等,

官方檔案地址:https://docs.spring.io/spring-cloud-gateway/docs/2.2.6.RELEASE/reference/html/
1.2、為啥用Gateway
Spring Cloud Gateway可以看做是一個Zuul 1.x的升級版和代替品,比Zuul 2更早的使用Netty實作異步IO,從而實作了一個簡單、比Zuul 1.x更高效的、與Spring Cloud緊密配合的API網關,Spring Cloud Gateway里明確的區分了Router和Filter,并且一個很大的特點是內置了非常多的開箱即用功能,并且都可以通過Spring Boot配置或者手工編碼鏈式呼叫來使用,
第二章 Gateway三大核心


第三章 Gateway作業流程

客戶端向Spring Cloud Gateway發出請求,然后在Gateway Handler Mapping中找到與請求相匹配的路由,將其發送到Gateway Web Handler,Handler再通過指定的過濾器鏈來將請求發送到我們實際的服務執行業務邏輯,然后回傳,過濾器之間用虛線分開是因為過濾器可能會在發送代理請求之前(“pre”)或之后(“post”)執行業務邏輯,
第四章 Gateway路由功能
4.1、專案準備與啟動
我們接下來的所有操作均是在Zuul最后完成的工程上進行操作,相關代碼請到配套資料中尋找,

打開已經準備好的專案以后,我們需要啟動以下服務,eureka-server7001啟動會報錯,暫時不用理會,等eureka-server7002啟動起來過一會就好了,
- eureka-server7001
- eureka-server7002
- service-provider8001
- service-provider8002
- service-consumer9001
- service-consumer9002

隨便訪問一個注冊中心,查看我們當前注冊的所有服務,登錄賬戶:root,登錄密碼:123456,訪問地址:http://localhost:7001

我們隨便訪問一個服務地址,訪問地址:http://localhost:9002/consumer/product/findByPid?pid=0

4.2、工程搭建與測驗
(1)在父工程spring-cloud-study下創建子工程gateway-cloud5002
(2)在剛創建好的子工程gateway-cloud5002的pom.xml中添加依賴:
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
(3)在剛創建好的子工程gateway-cloud5002中創建組態檔application.yaml,配置如下:
server:
port: 5002
spring:
application:
name: gateway-cloud5002
cloud:
gateway:
#開啟服務串列發現并擁有默認路由功能
discovery:
locator:
enabled: true
eureka:
client:
#是否將自己注冊到注冊中心,默認為 true
register-with-eureka: false
#表示 Eureka Client 間隔多久去服務器拉取注冊資訊,默認為 30 秒
registry-fetch-interval-seconds: 10
#設定服務注冊中心地址
service-url:
defaultZone: http://root:123456@eureka-server7001.com:7001/eureka/,http://root:123456@eureka-server7002.com:7002/eureka/
#日志記錄,在開發階段,建議開啟
logging:
level:
org.springframework.cloud.gateway: debug
org.springframework.http.server.reactive: debug
org.springframework.web.reactive: debug
(4)新建啟動類,在啟動類中加入以下代碼
@SpringBootApplication
public class GatewayCloud5002Application {
public static void main(String[] args) {
SpringApplication.run(GatewayCloud5002Application.class);
}
}
(5)啟動當前專案,這樣簡單的Gateway就搭建好了,我們可以通過默認的路由規則來訪問指定的服務方法,比如:
格式:“http://”+Gateway網關的域名+":"+Gateway網關的埠+"/"+微服務的名稱(一定大寫)+微服務的服務路徑(就是你Controller方法上標注的那個路徑)
例如:http://localhost:5002/SERVICE-CONSUMER9002/consumer/product/findAll
例如:http://localhost:5002/SERVICE-CONSUMER9003/consumer/product/findAll

4.3、配置自定義路由
現在,我們已經基本實作了Gateway默認路由的功能,但是,一般我們也可以自定義路由配置,為什么要自定義,細心的你會發現,現在你訪問指定的服務,必須要加注冊服務的名稱(例如:SERVICE-CONSUMER9002,SERVICE-CONSUMER9003),這個名稱可能很長,也可能會暴露你這個服務的一些性質,我們想要使用我們自己的路由規則,就必須使用自定義路由配置,自定義路由配置其實很簡單,只需要在gateway-cloud5002中的application.yaml加上相對應的路由配置就行了,具體代碼如下所示:
#這里只給出了區域配置,其他配置保持不變
spring:
application:
name: gateway-cloud5002
cloud:
gateway:
#開啟服務串列發現并擁有默認路由功能
discovery:
locator:
enabled: true
#自定義路由映射,可以配置多條路由規則,一個路由是由id、uri、predicates、filters組成
routes:
- id: SERVICE-CONSUMER9002-ROUTE #路由的ID,沒有固定規則但要求唯一,建議配合服務名
uri: http://localhost:9002 #匹配后提供服務的路由地址
predicates:
- Path=/consumer/product/find* #斷言,只有路徑相匹配才能進行路由
- id: SERVICE-CONSUMER9003-ROUTE #路由的ID,沒有固定規則但要求唯一,建議配合服務名
uri: http://localhost:9003 #匹配后提供服務的路由地址
predicates:
- Path=/consumer/product/miaoSha #斷言,只有路徑相匹配才能進行路由
如果你還有更多服務你還可以照著上邊的規則繼續往下寫(服務提供者和服務消費者都算服務),寫完后,請重新啟動當前的專案,然后依次訪問如下地址測驗:
地址1:http://localhost:5002/consumer/product/findAll
地址2:http://localhost:5002/consumer/product/miaoSha

4.4、禁止默認的路由
雖然實作了自定義路由設定,但是如果你使用之前默認的路由規則,他還是可以訪問的,我們想要禁用掉,默認的那個路由規則,只需要修改一段配置,如下:
#這里只給出了區域配置,其他配置保持不變
spring:
application:
name: gateway-cloud5002
cloud:
gateway:
#開啟服務串列發現并擁有默認路由功能,true開啟,false關閉,默認就是false,以下三行也可以洗掉或者注釋
discovery:
locator:
enabled: false
#自定義路由映射,可以配置多條路由規則,一個路由是由id、uri、predicates、filters組成
routes:
- id: SERVICE-CONSUMER9002-ROUTE #路由的ID,沒有固定規則但要求唯一,建議配合服務名
uri: http://localhost:9002 #匹配后提供服務的路由地址
predicates:
- Path=/consumer/product/find* #斷言,只有路徑相匹配才能進行路由
- id: SERVICE-CONSUMER9003-ROUTE #路由的ID,沒有固定規則但要求唯一,建議配合服務名
uri: http://localhost:9003 #匹配后提供服務的路由地址
predicates:
- Path=/consumer/product/miaoSha #斷言,只有路徑相匹配才能進行路由
重新啟動當前的專案,然后依次訪問如下地址測驗:
例如:http://localhost:5002/SERVICE-CONSUMER9002/consumer/product/findAll
例如:http://localhost:5002/SERVICE-CONSUMER9003/consumer/product/findAll

4.5、配置動態的路由
我們之前撰寫的自定義路由中的一項uri,我們直接寫的是目標服務的地址,這樣的寫法很死板,不靈活,我們能不能把目標uri不指向目標服務的地址,而是讓uri跟eureka的注冊應用掛鉤,這樣,你目標服務隨便擴容縮容,我網關這里感覺不到,因為網關直接找eureka,要想實作這樣的效果只需要修改uri為對應的注冊應用名稱就好,不過,我們還需要在這個注冊名稱之前加一個協議前綴,這個前綴可以使用配置修改,但是一般默認即可,具體配置如下:
#這里只給出了區域配置,其他配置保持不變
spring:
application:
name: gateway-cloud5002
cloud:
gateway:
#開啟服務串列發現并擁有默認路由功能
discovery:
locator:
enabled: false
#自定義路由映射,可以配置多條路由規則,一個路由是由id、uri、predicates、filters組成
routes:
- id: SERVICE-CONSUMER9002-ROUTE #路由的ID,沒有固定規則但要求唯一,建議配合服務名
#uri: http://localhost:9002 #匹配后提供服務的路由地址
uri: lb://SERVICE-CONSUMER9002 #uri的協議為lb,表示啟用Gateway的負載均衡功能,
predicates:
- Path=/consumer/product/find* #斷言,只有路徑相匹配才能進行路由
- id: SERVICE-CONSUMER9003-ROUTE #路由的ID,沒有固定規則但要求唯一,建議配合服務名
#uri: http://localhost:9003 #匹配后提供服務的路由地址
uri: lb://SERVICE-CONSUMER9003 #uri的協議為lb,表示啟用Gateway的負載均衡功能,
predicates:
- Path=/consumer/product/miaoSha #斷言,只有路徑相匹配才能進行路由
請重新啟動當前的專案,然后依次訪問如下地址測驗:
地址1:http://localhost:5002/consumer/product/findAll
地址2:http://localhost:5002/consumer/product/miaoSha

4.6、用代碼來配路由
Gateway網關路由有兩種配置方式,一種是使用組態檔的方式,另一種是使用代碼的方式來配置,具體代碼請參考:
com.caochenlei.config.GatewayConfig
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder) {
return routeLocatorBuilder.routes()
//可以使用通配符,例如:/provider/product/**
.route("SERVICE-PROVIDER-ROUTE1", r -> r.path("/provider/product/findAll").uri("lb://SERVICE-PROVIDER"))
.route("SERVICE-PROVIDER-ROUTE2", r -> r.path("/provider/product/findByPid").uri("lb://SERVICE-PROVIDER"))
.build();
}
}
請重新啟動當前的專案,然后依次訪問如下地址測驗:
地址1:http://localhost:5002/provider/product/findAll
地址2:http://localhost:5002/provider/product/findByPid?pid=0

4.7、為下章節做準備
下載地址:https://curl.se/windows/,如果下載失敗,請到配套資料中尋找該軟體,

解壓軟體:

配置環境變數:

測驗安裝狀態:

注釋當前配置:
#這里只給出了區域配置,其他配置保持不變
#spring:
# application:
# name: gateway-cloud5002
# cloud:
# gateway:
# #開啟服務串列發現并擁有默認路由功能
# discovery:
# locator:
# enabled: false
# #自定義路由映射,可以配置多條路由規則,一個路由是由id、uri、predicates、filters組成
# routes:
# - id: SERVICE-CONSUMER9002-ROUTE #路由的ID,沒有固定規則但要求唯一,建議配合服務名
# #uri: http://localhost:9002 #匹配后提供服務的路由地址
# uri: lb://SERVICE-CONSUMER9002 #uri的協議為lb,表示啟用Gateway的負載均衡功能,
# predicates:
# - Path=/consumer/product/find* #斷言,只有路徑相匹配才能進行路由
# - id: SERVICE-CONSUMER9003-ROUTE #路由的ID,沒有固定規則但要求唯一,建議配合服務名
# #uri: http://localhost:9003 #匹配后提供服務的路由地址
# uri: lb://SERVICE-CONSUMER9003 #uri的協議為lb,表示啟用Gateway的負載均衡功能,
# predicates:
# - Path=/consumer/product/miaoSha #斷言,只有路徑相匹配才能進行路由
第五章 Gateway斷言功能
5.1、謂詞:Path
謂詞介紹:通過請求路徑匹配,多個請求路徑可以使用逗號進行分隔,示例配置如下參考(拷貝完成請重啟應用):
#這里只給出了區域配置,其他配置保持不變
spring:
application:
name: gateway-cloud5002
cloud:
gateway:
routes:
- id: study-predicates-route
uri: lb://SERVICE-CONSUMER9002
predicates:
#匹配所有以/consumer/product/開頭的請求,匹配到以后使用Ribbon的負載均衡請求Eureka注冊中心的SERVICE-CONSUMER9002服務
- Path=/consumer/product/**
請求地址:curl -XGET http://localhost:5002/consumer/product/findAll

spring:
cloud:
gateway:
routes:
- id: host_route
uri: https://example.org
predicates:
- Path=/foo/{segment},/bar/{segment}
這個路由匹配這樣路徑的請求,比如:/foo/1 或 /foo/bar 或 /bar/baz
5.2、謂詞:After
謂詞介紹:該謂詞匹配在指定日期時間之后發生的請求,示例配置如下參考(拷貝完成請重啟應用):
#這里只給出了區域配置,其他配置保持不變
spring:
application:
name: gateway-cloud5002
cloud:
gateway:
routes:
- id: study-predicates-route
uri: lb://SERVICE-CONSUMER9002
predicates:
#匹配所有以/consumer/product/開頭的請求,匹配到以后使用Ribbon的負載均衡請求Eureka注冊中心的SERVICE-CONSUMER9002服務
- Path=/consumer/product/**
#匹配所有時間在2021年1月2日23點59分59秒以后訪問的請求,多個謂詞之間必須都符合才能通過
- After=2021-01-02T23:59:59.000+08:00[Asia/Shanghai]
生成時間:上邊的時間戳可以使用下邊這段代碼來進行生成,然后針對具體時間部分進行簡單修改,
public class ZonedDateTimeDemo {
public static void main(String[] args) {
ZonedDateTime zonedDateTime = ZonedDateTime.now();
System.out.println(zonedDateTime);
}
}
請求地址:curl -XGET http://localhost:5002/consumer/product/findAll

5.3、謂詞:Before
謂詞介紹:該謂詞匹配在指定日期時間之前發生的請求,示例配置如下參考(拷貝完成請重啟應用):
#這里只給出了區域配置,其他配置保持不變
spring:
application:
name: gateway-cloud5002
cloud:
gateway:
routes:
- id: study-predicates-route
uri: lb://SERVICE-CONSUMER9002
predicates:
#匹配所有以/consumer/product/開頭的請求,匹配到以后使用Ribbon的負載均衡請求Eureka注冊中心的SERVICE-CONSUMER9002服務
- Path=/consumer/product/**
#匹配所有時間在2021年2月2日23點59分59秒以前訪問的請求,多個謂詞之間必須都符合才能通過
- Before=2021-02-02T23:59:59.000+08:00[Asia/Shanghai]
請求地址:curl -XGET http://localhost:5002/consumer/product/findAll

5.4、謂詞:Between
謂詞介紹:該謂詞匹配在指定日期時間之間發生的請求,示例配置如下參考(拷貝完成請重啟應用):
#這里只給出了區域配置,其他配置保持不變
spring:
application:
name: gateway-cloud5002
cloud:
gateway:
routes:
- id: study-predicates-route
uri: lb://SERVICE-CONSUMER9002
predicates:
#匹配所有以/consumer/product/開頭的請求,匹配到以后使用Ribbon的負載均衡請求Eureka注冊中心的SERVICE-CONSUMER9002服務
- Path=/consumer/product/**
#匹配所有時間在2021年1月2日23點59分59秒以后,在2021年2月2日23點59分59秒以前訪問的請求,多個謂詞之間必須都符合才能通過
- Between=2021-01-02T23:59:59.000+08:00[Asia/Shanghai],2021-02-02T23:59:59.000+08:00[Asia/Shanghai]
請求地址:curl -XGET http://localhost:5002/consumer/product/findAll

5.5、謂詞:Cookie
謂詞介紹:可以接收兩個引數,一個是 Cookie name , 一個是正則運算式,路由規則會通過獲取對應的 Cookie name 值和正則運算式去匹配,如果匹配上就會執行路由,如果沒有匹配上則不執行,示例配置如下參考(拷貝完成請重啟應用):
#這里只給出了區域配置,其他配置保持不變
spring:
application:
name: gateway-cloud5002
cloud:
gateway:
routes:
- id: study-predicates-route
uri: lb://SERVICE-CONSUMER9002
predicates:
#匹配所有以/consumer/product/開頭的請求,匹配到以后使用Ribbon的負載均衡請求Eureka注冊中心的SERVICE-CONSUMER9002服務
- Path=/consumer/product/**
#你的請求必須帶有Cookie,并且其中有Cookie的名稱叫password,Cookie的值會跟你自己定義的Java正則匹配,這里的\d+,代表密碼必須為數字
- Cookie=password,\d+
正確請求地址:curl -XGET http://localhost:5002/consumer/product/findAll --cookie "password=123"

錯誤請求地址:curl -XGET http://localhost:5002/consumer/product/findAll --cookie "password=zhangsan"

5.6、謂詞:Header
謂詞介紹:Header謂詞和Cookie謂詞一樣,也是接收 2 個引數,一個 header 中屬性名稱和一個正則運算式,這個屬性值和正則運算式匹配則執行,示例配置如下參考(拷貝完成請重啟應用):
#這里只給出了區域配置,其他配置保持不變
spring:
application:
name: gateway-cloud5002
cloud:
gateway:
routes:
- id: study-predicates-route
uri: lb://SERVICE-CONSUMER9002
predicates:
#匹配所有以/consumer/product/開頭的請求,匹配到以后使用Ribbon的負載均衡請求Eureka注冊中心的SERVICE-CONSUMER9002服務
- Path=/consumer/product/**
#你的請求必須帶有Header,并且其中有Header的名稱叫Authorization,Header的值會跟你自己定義的Java正則匹配,這里的\d+,代表值必須為數字
- Header=Authorization,\d+
正確請求地址:curl -XGET http://localhost:5002/consumer/product/findAll -H "Authorization:123456789"

錯誤請求地址:curl -XGET http://localhost:5002/consumer/product/findAll -H "Authorization:zhangsan"

5.7、謂詞:Host
謂詞介紹:Host謂詞接收一組引數,一組匹配的域名串列,多個域名之間使用逗號分隔,它通過引數中的主機地址作為匹配規則,示例配置如下參考(拷貝完成請重啟應用):
#這里只給出了區域配置,其他配置保持不變
spring:
application:
name: gateway-cloud5002
cloud:
gateway:
routes:
- id: study-predicates-route
uri: lb://SERVICE-CONSUMER9002
predicates:
#匹配所有以/consumer/product/開頭的請求,匹配到以后使用Ribbon的負載均衡請求Eureka注冊中心的SERVICE-CONSUMER9002服務
- Path=/consumer/product/**
#如果請求的Host標頭值為www.somehost.org或beta.somehost.org或此路由匹配www.anotherhost.org,匹配通過才可路由
- Host=**.somehost.org,**.anotherhost.org
正確請求地址:curl -XGET http://localhost:5002/consumer/product/findAll -H "Host:www.somehost.org"

錯誤請求地址:curl -XGET http://localhost:5002/consumer/product/findAll -H "Host:www.baidu.com"

5.8、謂詞:Method
謂詞介紹:該謂詞可以通過你請求的方式(GET、POST、PUT、DELETE、…)來進行匹配,只有指定方式的請求才可以匹配成功,示例配置如下參考(拷貝完成請重啟應用):
#這里只給出了區域配置,其他配置保持不變
spring:
application:
name: gateway-cloud5002
cloud:
gateway:
routes:
- id: study-predicates-route
uri: lb://SERVICE-CONSUMER9002
predicates:
#匹配所有以/consumer/product/開頭的請求,匹配到以后使用Ribbon的負載均衡請求Eureka注冊中心的SERVICE-CONSUMER9002服務
- Path=/consumer/product/**
#如果請求型別是GET或者POST請求才能匹配成功,其他請求型別均失敗,失敗就會404
- Method=GET,POST
正確請求地址:curl -XGET http://localhost:5002/consumer/product/findAll
正確請求地址:curl -XPOST http://localhost:5002/consumer/product/findAll

錯誤請求地址:curl -XPUT http://localhost:5002/consumer/product/findAll
錯誤請求地址:curl -XDELETE http://localhost:5002/consumer/product/findAll

5.9、謂詞:Query
謂詞介紹:該謂詞也支持傳入兩個引數,一個是屬性名一個為屬性值,屬性值可以是正則運算式,示例配置如下參考(拷貝完成請重啟應用):
#這里只給出了區域配置,其他配置保持不變
spring:
application:
name: gateway-cloud5002
cloud:
gateway:
routes:
- id: study-predicates-route
uri: lb://SERVICE-CONSUMER9002
predicates:
#匹配所有以/consumer/product/開頭的請求,匹配到以后使用Ribbon的負載均衡請求Eureka注冊中心的SERVICE-CONSUMER9002服務
- Path=/consumer/product/**
#如果請求引數中包含smile引數,并且smile引數必須符合逗號后邊的正則運算式的值,只有匹配成功才可以路由
- Query=smile,\d+
正確請求地址:curl -XGET http://localhost:5002/consumer/product/findAll?smile=521

錯誤請求地址:curl -XGET http://localhost:5002/consumer/product/findAll?smile=no

5.10、謂詞:RemoteAddr
謂詞介紹:該謂詞支持通過設定某個 ip 區間號段,支持單個 ip 地址,還支持接受 cidr 符號 (IPv4 或 IPv6) 字串的串列(最小大小為 1),例如 192.168.0.1/16 (其中 192.168.0.1 是客戶端發送請求的 ip 地址,16 是子網掩碼(255.255.0.0)),示例配置如下參考(拷貝完成請重啟應用):
#這里只給出了區域配置,其他配置保持不變
spring:
application:
name: gateway-cloud5002
cloud:
gateway:
routes:
- id: study-predicates-route
uri: lb://SERVICE-CONSUMER9002
predicates:
#匹配所有以/consumer/product/開頭的請求,匹配到以后使用Ribbon的負載均衡請求Eureka注冊中心的SERVICE-CONSUMER9002服務
- Path=/consumer/product/**
#請求必須是192.168.1.3,并且子網掩碼為255.255.255.0的地址發出的才可以路由
- RemoteAddr=192.168.1.3/24
查看本機以太網的ipv4地址以及子網掩碼,使用ipconfig命令:

正確請求地址:curl -XGET http://192.168.1.3:5002/consumer/product/findAll

錯誤請求地址:curl -XGET http://localhost:5002/consumer/product/findAll

5.11、謂詞:Weight
謂詞介紹:該Weight謂詞有兩個引數:group和weight(一個int),權重是按組計算的,以下示例配置權重路由謂詞:
#這里只給出了區域配置,其他配置保持不變
spring:
cloud:
gateway:
routes:
- id: weight_high
uri: https://weighthigh.org
predicates:
- Weight=group1, 8
- id: weight_low
uri: https://weightlow.org
predicates:
- Weight=group1, 2
這條路線會將大約80%的流量轉發到weighthigh.org,將大約20%的流量轉發到weightlow.org,
第六章 Gateway過濾功能
Spring Cloud Gateway根據作用域劃分為GatewayFilter和GlobalFilter兩類,
6.1、內置的網關過濾器
GatewayFilter:網關過濾器,需要通過spring.cloud.routes.filters配置在具體路由下,只作用在當前路由上或通過spring.cloud.default-filters配置在全域,作用在所有路由上,內置有好幾十種網關過濾器,我們在這里只講解最常見到的幾種過濾器,
官網過濾器串列:https://docs.spring.io/spring-cloud-gateway/docs/2.2.6.RELEASE/reference/html/#gatewayfilter-factories

6.1.1、RewritePath
過濾器介紹:RewritePath 網關過濾器工廠采用路徑正則運算式引數和一個替換引數,使用 Java 正則運算式靈活地重寫請求路徑,示例配置如下參考(拷貝完成請重啟應用):
#這里只給出了區域配置,其他配置保持不變
spring:
application:
name: gateway-cloud5002
cloud:
gateway:
routes:
- id: study-predicates-route
uri: lb://SERVICE-CONSUMER9002
predicates:
#匹配請求地址以/api-gateway/開頭的請求,實際上,我們后邊SERVICE-CONSUMER9002中根本就沒有以/api-gateway/開頭的請求
#你直接訪問,例如:http://localhost:5002/api-gateway/consumer/product/findAll,你訪問肯定報404
#你要是訪問這個地址也能訪問成功對應的業務,那你就需要使用正則運算式,把真正的請求地址提取出來,然后重寫,然后再訪問
- Path=/api-gateway/**
filters:
#(?<segment>/?.*)就相當于一個模板引數,用來匹配/**這里的路徑,可以是多級,然后重寫到逗號后邊的那個$\{segment}地址
#這里本應該是直接參考${segment},但是由于YAML規范,$應將替換$\
#如果訪問的是http://localhost:5002/api-gateway/consumer/product/findAll
#那么(?<segment>/?.*)就代表了:/consumer/product/findAll
#經過重寫之后就是http://localhost:5002/consumer/product/findAll,這樣我們就能正常訪問對應的業務了
- RewritePath=/api-gateway(?<segment>/?.*), $\{segment}
在瀏覽器輸入對應的地址進行測驗:http://localhost:5002/api-gateway/consumer/product/findAll

6.1.2、StripPrefix
過濾器介紹:StripPrefix 網關過濾器采用一個引數StripPrefix,該引數表示在將請求發送到下游之前從請求中剝離的路徑個數,示例配置如下參考(拷貝完成請重啟應用):
#這里只給出了區域配置,其他配置保持不變
spring:
application:
name: gateway-cloud5002
cloud:
gateway:
routes:
- id: study-predicates-route
uri: lb://SERVICE-CONSUMER9002
predicates:
#匹配請求地址以/api-gateway/開頭的請求,實際上,我們后邊SERVICE-CONSUMER9002中根本就沒有以/api-gateway/開頭的請求
#你直接訪問,例如:http://localhost:5002/api-gateway/consumer/product/findAll,你訪問肯定報404
#你要是訪問這個地址也能訪問成功對應的業務,我們還有一種方法,可以直接忽略/api-gateway,/**該怎么請求還怎么請求
- Path=/api-gateway/**
filters:
#你想要跳過幾層就寫幾,注意,這個不是從0開始的
- StripPrefix=1
在瀏覽器輸入對應的地址進行測驗:http://localhost:5002/api-gateway/consumer/product/findAll

6.1.3、PrefixPath
過濾器介紹:PrefixPath 網關過濾器為指定匹配的路徑添加統一前綴,示例配置如下參考(拷貝完成請重啟應用):
#這里只給出了區域配置,其他配置保持不變
spring:
application:
name: gateway-cloud5002
cloud:
gateway:
routes:
- id: study-predicates-route
uri: lb://SERVICE-CONSUMER9002
predicates:
- Path=/**
filters:
- PrefixPath=/consumer/product
在瀏覽器輸入對應的地址進行測驗:http://localhost:5002/findAll

6.1.4、SetPath
過濾器介紹:SetPath 網關過濾器采用路徑模板引數,它提供了一 種通過允許模板化路徑段來操作請求路徑的簡單方法,使用了Spring Framework中的URI模板,允許多個匹配段,示例配置如下參考(拷貝完成請重啟應用):
#這里只給出了區域配置,其他配置保持不變
spring:
application:
name: gateway-cloud5002
cloud:
gateway:
routes:
- id: study-predicates-route
uri: lb://SERVICE-CONSUMER9002
predicates:
- Path=/{segment}
filters:
#拿到{segment}重寫路徑/consumer/product/{segment}
- SetPath=/consumer/product/{segment}
在瀏覽器輸入對應的地址進行測驗:http://localhost:5002/findAll

6.1.5、SetStatus
過濾器介紹:SetStatus過濾器可以在回應后設定回應狀態碼,示例配置如下參考(拷貝完成請重啟應用):
#這里只給出了區域配置,其他配置保持不變
spring:
application:
name: gateway-cloud5002
cloud:
gateway:
routes:
- id: study-predicates-route
uri: lb://SERVICE-CONSUMER9002
predicates:
- Path=/consumer/product/**
filters:
#訪問無論成不成功,都回傳404
- SetStatus=404
在瀏覽器輸入對應的地址進行測驗:http://localhost:5002/consumer/product/findAll

6.1.6、AddRequestParameter
過濾器介紹:在用戶請求的時候可以給用戶添加請求引數,示例配置如下參考(拷貝完成請重啟應用):
#這里只給出了區域配置,其他配置保持不變
spring:
application:
name: gateway-cloud5002
cloud:
gateway:
routes:
- id: study-predicates-route
uri: lb://SERVICE-CONSUMER9002
predicates:
- Path=/consumer/product/**
filters:
#/consumer/product/findByPid,后邊必須帶一個引數pid,我們也可以不帶,給他設定一個默認值
- AddRequestParameter=pid,0
在瀏覽器輸入對應的地址進行測驗:http://localhost:5002/consumer/product/findByPid

6.1.7、AddRequestHeader
過濾器介紹:對于所有匹配的請求,將會給傳給下游的請求添加一個請求頭 X-Request-Foo:Bar,這里就不演示了,
#這里只給出了區域配置,其他配置保持不變
spring:
application:
name: gateway-cloud5002
cloud:
gateway:
routes:
- id: study-predicates-route
uri: lb://SERVICE-CONSUMER9002
predicates:
- Path=/consumer/product/**
filters:
- AddRequestHeader=X-Request-Foo,Bar
6.1.8、AddResponseHeader
過濾器介紹:對于所有匹配的請求,添加一個回應頭 X-Response-Foo:Bar,這里就不演示了,
#這里只給出了區域配置,其他配置保持不變
spring:
application:
name: gateway-cloud5002
cloud:
gateway:
routes:
- id: study-predicates-route
uri: lb://SERVICE-CONSUMER9002
predicates:
- Path=/consumer/product/**
filters:
- AddResponseHeader=X-Response-Foo,Bar
6.2、內置的全域過濾器
GlobalFilter:全域過濾器,不需要在組態檔中配置,作用在所有的路由上,最終通過GatewayFilterAdapter包裝成GatewayFilterChain可識別的過濾器,它為請求業務以及路由的URI轉換為真實業務服務請求地址的核心過濾器,不需要配置系統初始化時加載,并作用在每個路由上,
官網過濾器串列:https://docs.spring.io/spring-cloud-gateway/docs/2.2.6.RELEASE/reference/html/#global-filters

6.3、自定義網關過濾器
6.3.1、創建過濾器
自定義網關過濾器需要實作兩個介面:GatewayFilter、Ordered,
com.caochenlei.filter.MyGatewayFilter
public class MyGatewayFilter implements GatewayFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("==========自定義網關過濾器開始==========");
System.out.println(exchange.getRequest().getPath());
System.out.println("==========自定義網關過濾器結束==========");
return chain.filter(exchange);
}
//過濾器鏈執行順序,數值越小,執行順序越靠前
@Override
public int getOrder() {
return 0;
}
}
6.3.2、注冊過濾器
修改全域組態檔中的使用代碼進行路由的部分,代碼如下:
com.caochenlei.config.GatewayConfig
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder) {
return routeLocatorBuilder.routes()
//可以使用通配符,例如:/provider/product/**
.route("SERVICE-PROVIDER-ROUTE1",
r -> r.path("/provider/product/findAll")
.uri("lb://SERVICE-PROVIDER")
.filter(new MyGatewayFilter())
)
.route("SERVICE-PROVIDER-ROUTE2",
r -> r.path("/provider/product/findByPid")
.uri("lb://SERVICE-PROVIDER")
.filter(new MyGatewayFilter())
)
.build();
}
}
6.3.3、測驗過濾器
重啟當前應用,打開瀏覽器進行訪問:http://localhost:5002/provider/product/findAll

6.4、自定義全域過濾器
6.4.1、創建過濾器
自定義網關過濾器需要實作兩個介面:GlobalFilter、Ordered,
com.caochenlei.filter.MyGlobalFilter
@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("==========自定義全域過濾器開始==========");
System.out.println(exchange.getRequest().getPath());
System.out.println("==========自定義全域過濾器結束==========");
return chain.filter(exchange);
}
//過濾器鏈執行順序,數值越小,執行順序越靠前
@Override
public int getOrder() {
return 0;
}
}
6.4.2、注冊過濾器
全域過濾器不用注冊,因為過濾器類上有@Component,
6.4.3、測驗過濾器
重啟當前應用,打開瀏覽器進行訪問:http://localhost:5002/provider/product/findAll

第七章 Gateway熔斷降級
7.1、熔斷降級含義
熔斷降級:在分布式系統中,網關作為流量的入口,大量請求進入網關,向后端遠程系統或服務發起呼叫,后端服務不可避免的會產生呼叫失敗(超時或者例外),失敗時不能讓請求堆積在網關上,需要快速失敗并回傳回去,這就需要在網關上做熔斷、降級操作,
7.2、添加依賴檔案
pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
7.3、撰寫組態檔
application.yaml
#這里只給出了區域配置,其他配置保持不變
spring:
application:
name: gateway-cloud5002
cloud:
gateway:
routes:
- id: study-predicates-route
uri: lb://SERVICE-CONSUMER9002
predicates:
- Path=/consumer/product/**
filters:
- name: Hystrix
args:
name: default
fallbackUri: 'forward:/defaultFallback' #服務降級轉發到/defaultFallback
# hystrix 信號量隔離,2秒后自動超時
hystrix:
shareSecurityContext: true
command:
default:
execution:
isolation:
strategy: SEMAPHORE
thread:
timeoutInMilliseconds: 2000
7.4、撰寫降級方法
com.caochenlei.controller.DefaultHystrixController
@RestController
public class DefaultHystrixController {
@RequestMapping("/defaultFallback")
public Map<String, String> defaultFallback() {
Map<String, String> map = new HashMap<>();
map.put("code", "500");
map.put("msg", "服務降級");
map.put("data", "null");
return map;
}
}
7.5、網關熔斷測驗
重新啟動當前應用,然后快速重繪錯誤的地址,我們這里連刷20回(為了更好的出效果),然后你再快速重繪正常的地址,發現正常的地址也不能訪問,沒有關系,繼續重繪,慢慢的,該服務又恢復了正常,這就是服務熔斷,在這里,我不好截圖,只貼出正常地址和錯誤地址,自己測驗吧,
錯誤地址:http://localhost:5002/consumer/product/findByPid?pid=-1
正常地址:http://localhost:5002/consumer/product/findByPid?pid=0
超時地址:http://localhost:5002/consumer/product/findByPid?pid=1
最終呼叫的業務模擬了各種的邏輯:

7.6、網關降級測驗
我們手動把service-consumer9002停止,模擬目標服務宕機,然后訪問正常地址,觀察頁面:http://localhost:5002/consumer/product/findByPid?pid=0

測驗完成以后,你需要把service-consumer9002重新啟動,
第八章 Gateway網關限流
8.1、網關限流含義
網關上有大量請求,對指定服務進行限流,可以很大程度上提高服務的可用性與穩定性,限流的目的是通過對并發訪問/請求進行限速,或對一個時間視窗內的請求進行限速來保護系統,一旦達到限制速率則可以拒絕服務、排隊或等待、降級,
8.2、網關限流演算法
一般來說,實作網關限流有三種常見的演算法:
計數器演算法:
計數器演算法是限流演算法里最簡單也是最容易實作的一種演算法,比如我們規定,對于A介面來說,我們1分鐘的訪問次數不能超過100個,那么我們可以這么做:在一開始的時候,我們可以設定一個計數器 counter,每當一個請求過來的時候,counter就加1,如果counter的值大于100并且該請求與第一個請求的間隔時間還在 1分鐘之內,觸發限流,如果該請求與第一個請求的間隔時間大于1分鐘,重置counter重新計數,具體演算法的示意圖如下:

這個演算法雖然簡單,但是有一個十分致命的問題,那就是臨界問題,我們看下圖:

從上圖中我們可以看到,假設有一個惡意用戶,他在0:59時,瞬間發送了100個請求,并且1:00又瞬間發送了100個請求,那么其實這個用戶在1秒里面,瞬間發送了200個請求,我們剛才規定的是1分鐘最多100個請求,也就是每秒鐘最多1.7個請求,用戶通過在時間視窗的重置節點處突發請求,可以瞬間超過我們的速率限制,用戶有可能通過演算法的這個漏洞,瞬間壓垮我們的應用,除了安全問題以外,還存在資源分配不均的問題,如果你前30秒鐘就用完了100個請求,就會導致后30秒無法請求服務等等問題,
桶漏演算法:
漏桶演算法其實也很簡單,可以粗略的認為就是注水漏水的程序,往桶中以任意速率流入水,以一定速率流出水,當水超過桶流量則丟棄,因為桶容量是不變的,保證了整體的速率,具體演算法的示意圖如下:

桶漏演算法是使用佇列機制實作的,

這種演算法也有問題,當大量的請求堆積到網關這里,很有可能導致網關服務不可用,并且后續的請求也無法進入到佇列桶中,導致請求的丟失,
令牌桶演算法:
令牌桶演算法是對漏桶演算法的一種改進,漏桶演算法能夠限制請求呼叫的速率,而令牌桶演算法能夠在限制呼叫的平均速率的同時還允許一定程度的突發呼叫,在令牌桶演算法中,存在一個桶,用來存放固定數量的令牌,演算法中存在一種機制,以一定的速率往桶中放令牌,每次請求呼叫需要先獲取令牌,只有拿到令牌,才有機會繼續執行,否則選擇選擇等待可用的令牌、或者直接拒絕,放令牌這個動作是持續不斷的進行,如果桶中令牌數達到上限,就丟棄令牌,
他運用的場景大概是這樣的:桶中一直有大量的可用令牌,這時進來的請求可以直接拿到令牌執行,比如設定QPS為100/s,那么限流器初始化完成一秒后,桶中就已經有100個令牌了,等服務啟動完成對外提供服務時,該限流器可以抵擋瞬時的100個請求,當桶中沒有令牌時,請求會進行等待,最后相當于以一定的速率執行,
Spring Cloud Gateway內部使用的就是該演算法,大概描述如下:
- 所有的請求在處理之前都需要拿到一個可用的令牌才會被處理,
- 根據限流大小,設定按照一定的速率往桶里添加令牌,
- 桶設定最大的放置令牌限制,當桶滿時、新添加的令牌就被丟棄或者拒絕,
- 請求到達后首先要獲取令牌桶中的令牌,拿著令牌才可以進行其他的業務邏輯,處理完業務邏輯之后,將令牌直接洗掉,
- 令牌桶有最低限額,當桶中的令牌達到最低限額的時候,請求處理完之后將不會洗掉令牌,以此保證足夠的限流,

8.3、添加依賴檔案
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
8.4、撰寫組態檔
application.yaml
#這里只給出了區域配置,其他配置保持不變
spring:
application:
name: gateway-cloud5002
redis:
host: localhost
port: 6379
database: 0
lettuce:
pool:
max-active: 1024 #最大連接數
max-wait: 10000 #最大等待時間,單位毫秒
max-idle: 256 #最大空閑連接
min-idle: 8 #最小空閑連接
cloud:
gateway:
#路由配置
routes:
- id: study-predicates-route
uri: lb://SERVICE-CONSUMER9002
predicates:
- Path=/consumer/product/**
filters:
#服務的熔斷和降級配置(內置的過濾器)
- name: Hystrix
args:
name: default
fallbackUri: 'forward:/defaultFallback' #服務降級轉發到/defaultFallback
#網關的限流過濾器配置(內置的過濾器)
- name: RequestRateLimiter
args:
key-resolver: '#{@pathKeyResolver}' #使用 SpEL 運算式按名稱參考bean,一共有三種,名稱請查看配置物件
redis-rate-limiter.replenishRate: 1 #令牌桶每秒填充速率
redis-rate-limiter.burstCapacity: 2 #令牌桶總的容量大小,寫2方便測驗
com.caochenlei.config.GatewayConfig
@Configuration
public class GatewayConfig {
...
...
/**
* 如果你想要根據用戶的ip地址來限流,請打開這個@Bean注解,三種方式不能同時存在
* application.yaml請配置,key-resolver: '#{@ipKeyResolver}'
*/
//@Bean
public KeyResolver ipKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
}
/**
* 如果你想要根據用戶的名稱來限流,請打開這個@Bean注解,但是,請求地址一定要包含userId這個引數,三種方式不能同時存在
* application.yaml請配置,key-resolver: '#{@userKeyResolver}'
* 注意:此種方式并不是一定是userId,你可以指定任意引數名稱,前提是你的請求中一定要包含該引數,所以這種方法又叫做根據請求引數限流
*/
//@Bean
KeyResolver userKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("userId"));
}
/**
* 如果你想要根據用戶的請求地址來限流,請打開這個@Bean注解,三種方式不能同時存在
* application.yaml請配置,key-resolver: '#{@pathKeyResolver}'
*/
@Bean
KeyResolver pathKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getPath().value());
}
}
8.5、啟動redis應用
Windows版本的Redis請在此地址下載:https://github.com/MicrosoftArchive/redis/releases,如果下載失敗,請到配套資料中尋找該軟體,

下載完成以后,請你解壓到一個不包含中文以及空格的目錄當中,然后在此路徑下使用cmd命令列的方式啟動Redis應用:

8.6、網關限流測驗
請重新啟動當前應用,然后在瀏覽器的地址中快速重繪4次(桶內容量2個,每秒生成1個,重繪4次保險,有可能在第3次的時候就已經限流了),
正常業務地址:http://localhost:5002/consumer/product/findByPid?pid=0


第九章 Gateway跨域問題
您可以配置網關以控制CORS行為,“全域” CORS配置是URL模式到Spring Framework CorsConfiguration的映射,以下示例配置了CORS:
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
# 允許攜帶認證資訊
# 允許跨域的源(網站域名/ip),設定*為全部
# 允許跨域請求里的head欄位,設定*為全部
# 允許跨域的method, 默認為GET和OPTIONS,設定*為全部
# 跨域允許的有效期
allow-credentials: true
allowed-origins:
- "http://localhost:9002"
- "http://localhost:9003"
allowed-headers: "*"
allowed-methods:
- OPTIONS
- GET
- POST
max-age: 3600
#exposed-headers:
# 允許response的head資訊
# 默認僅允許如下6個:
# Cache-Control
# Content-Language
# Content-Type
# Expires
# Last-Modified
# Pragma
第十章 Gateway統一鑒權
關于網關訪問時必須要統一驗證請求是否有效時,有很多種辦法,我這里給出Spring Boot+Spring Security+JWT實作單點登錄的解決思路來實作網關統一驗證,
學習地址:https://caochenlei.blog.csdn.net/article/details/112973713
實作思路:
- 創建一個網關認證的服務,來統一進行登錄認證,認證成功給用戶回傳一個token值,
- 在每一個網關中,都創建一個全域過濾器,這個過濾器的作用就是獲取用戶請求時所帶來的
token值,然后對token的有效性進行驗證, - 驗證成功就繼續執行過濾器鏈,驗證失敗就直接給用戶回應一個
json串資料,告訴用戶認證失敗,
注意:這種方法可以應用到網關集群模式,因為每一個網關只負責校驗
token,并不做認證處理,認證都統一在網關認證服務中來完成,網關集群的搭建沒啥特別的,最后再上線的時候,在使用nginx在對網關進行一層負載均衡處理,這樣,一個高可用的網關集群就搭建好了,在這里,我就不詳細貼出代碼了,上邊提供的那一片文章寫的很詳細,如果你是真的有需要,可以留言,后續我在更新此章節,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/256417.html
標籤:其他
