學習目標
第1章 網(wǎng)關(guān)
1.1 網(wǎng)關(guān)的概念
簡單來說,網(wǎng)關(guān)就是一個網(wǎng)絡(luò)連接到另外一個網(wǎng)絡(luò)的“關(guān)口”。如下圖所示,當我們所在的本地網(wǎng)絡(luò)(局域網(wǎng))要訪問外部網(wǎng)絡(luò)的數(shù)據(jù)時,需要通過路由器進行轉(zhuǎn)發(fā),而這里的路由器就充當了網(wǎng)關(guān)的角色。
1.2 網(wǎng)關(guān)的作用
網(wǎng)關(guān)的作用,是可以實現(xiàn)不同網(wǎng)絡(luò)之間的互聯(lián),同時,還可以使得在不同的通信協(xié)議、數(shù)據(jù)格式等系統(tǒng)之間實現(xiàn)轉(zhuǎn)發(fā)。
我們今天要講解的Gateway,它也是網(wǎng)關(guān)的一種,我們稱為應(yīng)用網(wǎng)關(guān),也稱為API網(wǎng)關(guān)。為什么需要API網(wǎng)關(guān)呢? 還得從架構(gòu)演變過程來說明:
前面我們說過,在微服務(wù)架構(gòu)中,每個微服務(wù)都是一個獨立運行的組件,這些組件通過Rest API風格的接口給到H5、Android、IOS等客戶端程序調(diào)用。(移動互聯(lián)時代,為了盡快迭代)。而在一個UI界面中,通常會展示很多數(shù)據(jù),這些數(shù)據(jù)可能來自不同的微服務(wù),比如在一個電商系統(tǒng)中,執(zhí)行一個下單請求,必然需要
1.3 出現(xiàn)的背景
那么早期的微服務(wù)架構(gòu),面對這樣的情況的處理方式,出現(xiàn)了如下圖所示的調(diào)用方式。
在這種調(diào)用方式中,不難發(fā)現(xiàn)問題會比較多:
這種方式存在較多的問題,所以一般我們會在客戶端與微服務(wù)之間引入BFF層(即 Backend For Frontend(服務(wù)于前端的后端)),也就是服務(wù)器設(shè)計API時會考慮前端的使用,并在服務(wù)端直接進行業(yè)務(wù)邏輯的處理,又稱為用戶體驗適配器。
如下圖所示,BFF層為客戶端提供了統(tǒng)一的聚合服務(wù),我們可以在BFF層為不同的端或者不同的業(yè)務(wù)提供更加友好和統(tǒng)一的客戶端。
引入BFF層的好處是
但是這種方式仍然存在問題,客戶端發(fā)起請求進入到BFF層時,需要考慮到安全問題,需要做鑒權(quán)、限流等,而這些功能需要在每一個BFF模塊中都需要編寫,增加了很多的重復(fù)代碼,而且維護起來非常不靈活導致開發(fā)效率下降。
所以,引入了API網(wǎng)關(guān),整體結(jié)構(gòu)如下圖所示
網(wǎng)關(guān)是微服務(wù)架構(gòu)不可或缺的一部分,作為微服務(wù)架構(gòu)的唯一入口,將所有請求轉(zhuǎn)發(fā)到后端對應(yīng)的微服務(wù)上去,同時又可以將各個微服務(wù)中的通用功能集中到網(wǎng)關(guān)去做,而不是在每個微服務(wù)都實現(xiàn)一遍,
同時,增加網(wǎng)關(guān)后,把各個BFF模塊的橫切功能剝離到網(wǎng)關(guān)中,BFF模塊開發(fā)人員只需要關(guān)注在業(yè)務(wù)邏輯的交付上。
常見的開源網(wǎng)關(guān)
1.4 Gateway簡介
Spring Cloud Gateway 是 Spring 官方團隊研發(fā)的 API 網(wǎng)關(guān)技術(shù),它的目的是取代 Zuul 為微服務(wù)提供一種簡單高效的 API 網(wǎng)關(guān)。一般來說,Spring 團隊不會重復(fù)造輪子,為什么又研發(fā)出一個 Spring Cloud Gateway 呢?有幾方面原因。
- Zuul1.x 采用的是傳統(tǒng)的 thread per connection 方式來處理請求,也就是針對每一個請求,會為這個請求專門分配一個線程來進行處理,直到這個請求完成之后才會釋放線程,一旦后臺服務(wù)器響應(yīng)較慢,就會使得該線程被阻塞,所以它的性能不是很好。
- Zuul 本身存在的一些性能問題不適合于高并發(fā)的場景,雖然后來 Netflix 決定開發(fā)高性能版 Zuul 2.x,但是 Zuul 2.x 的發(fā)布時間一直不確定。雖然 Zuul 2.x 后來已經(jīng)發(fā)布并且開源了,但是 Spring Cloud 并沒有打算集成進來。Spring Cloud Gateway 是依賴于 Spring Boot 2.0、Spring WebFlux 和 Project Reactor 等技術(shù)開發(fā)的網(wǎng)關(guān),它不僅提供了統(tǒng)一的路由請求的方式,還基于過濾鏈的方式提供了網(wǎng)關(guān)最基本的功能。
1.5 Gateway基本概念
Spring Cloud Gateway的基本工作原理如下圖所示。
客戶端向Spring Cloud Gateway發(fā)出請求。然后在Gateway Handler Mapping中找到與請求相匹配的路由,將其發(fā)送到Gateway Web Handler。Handler 再通過指定的過濾器鏈來將請求發(fā)送到我們實際的服務(wù)執(zhí)行業(yè)務(wù)邏輯,然后返回。
過濾器之間用虛線分開是因為過濾器可能會在發(fā)送代理請求之前(“pre”)或之后(“post”)執(zhí)行業(yè)務(wù)邏輯。
- Filter在“pre”類型的過濾器可以做參數(shù)校驗、權(quán)限校驗、流量監(jiān)控、日志輸出、協(xié)議轉(zhuǎn)換等,
- 在“post”類型的過濾器中可以做響應(yīng)內(nèi)容、響應(yīng)頭的修改,日志的輸出,流量監(jiān)控等有著非常重要的作用。
在Spring Cloud Gateway中有三個重要的對象,分別是:
- Route路由,它是網(wǎng)關(guān)的基礎(chǔ)元素,包含ID、目標URI、斷言、過濾器組成,當前請求到達網(wǎng)關(guān)時,會通過Gateway Handler Mapping,基于斷言進行路由匹配,當斷言為true時,匹配到路由進行轉(zhuǎn)發(fā)
- Predicate斷言,學過java8的同學應(yīng)該知道這個函數(shù),它可以允許開發(fā)人員去匹配HTTP請求中的元素,一旦匹配為true,則表示匹配到合適的路由進行轉(zhuǎn)發(fā)
- Filter過濾器,可以在請求發(fā)出的前后進行一些業(yè)務(wù)上的處理,比如授權(quán)、埋點、限流等。
具體的工作原理如下圖所示:
它的整體工作原理如下。
其中,predicate就是我們的匹配條件;而filter,就可以理解為一個無所不能的攔截器。有了這兩個元素,再加上目標uri,就可以實現(xiàn)一個具體的路由了。
客戶端向 Spring Cloud Gateway 發(fā)出請求,如果請求與網(wǎng)關(guān)程序定義的路由匹配,則該請求就會被發(fā)送到網(wǎng)關(guān) Web 處理程序,此時處理程序運行特定的請求過濾器鏈。
過濾器之間用虛線分開的原因是過濾器可能會在發(fā)送代理請求的前后執(zhí)行邏輯。所有 pre 過濾器邏輯先執(zhí)行,然后執(zhí)行代理請求;代理請求完成后,執(zhí)行 post 過濾器邏輯。
第2章 Predicate應(yīng)用
下面我們通過一些案例演示來初步了解Spring Cloug Gateway.
1.在上文的基礎(chǔ)之上,整個項目拷貝過來,并改名為gateway-**
2.在上面的框架基礎(chǔ)之上,修改user項目中的HelloController和UserController
@RestControllerpublic class HelloController { @Autowired OrderServiceClient orderServiceClient; @Value(“${server.port}”) private int port; @GetMapping(“/hello/{name}”) public String get(@PathVariable(“name”) String name){ String result = “”; //同步 result = new HelloCommand(name,orderServiceClient).execute(); return “當前user端口為:”+port+”,結(jié)果為:”+result; }}@RestControllerpublic class UserController { @Autowired OrderServiceClient orderServiceClient; @Value(“${server.port}”) private int port; @HystrixCommand(commandProperties = { @HystrixProperty(name=”circuitBreaker.requestVolumeThreshold”,value = “10”), @HystrixProperty(name=”circuitBreaker.sleepWindowInMilliseconds”,value=”5000″), @HystrixProperty(name=”circuitBreaker.errorThresholdPercentage”,value=”50″), },fallbackMethod = “fallback”) @GetMapping(“/get/{num}”) public String get(@PathVariable(“num”) int num){ if(num%2==0){ return “當前user端口為:”+port+”,結(jié)果為:正常訪問”; } return “當前user端口為:”+port+”,結(jié)果為:”+orderServiceClient.orderLists(num); } public String fallback(int num){ return “觸發(fā)降級”; }}
并分別開啟兩個user項目,端口為8080和8081;開啟兩個order項目,端口分別為8088和8099
3.創(chuàng)建新的springboot項目gateway-common
4.配置pom
4.0.0 eclipse2019-demo com.example 1.0-SNAPSHOT com.example gateway-common 0.0.1-SNAPSHOT gateway-common Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-test test org.springframework.cloud spring-cloud-starter-gateway org.springframework.cloud spring-cloud-starter-netflix-eureka-client
5.配置yml,如果用的是nacos,一般這些配置可以寫在nacos里面
server: port: 9527 spring: application: name: gateway cloud: gateway: routes: # 路由的ID,沒有固定規(guī)則但要求唯一,建議配合服務(wù)名 – id: getUser # 匹配后提供服務(wù)的路由地址 uri: http://localhost:8080 # 斷言,路徑相匹配的進行路由 predicates: – Path=/get/** – id: sayHello uri: http://localhost:8081 predicates: – Path=/hello/** – id: heihei uri: https://www.baidu.com/ predicates: – Path=/heihei/** filters: – StripPrefix=1 #去掉地址中的第一部分 – StripPrefix=2 #去掉地址中的第二部分eureka: instance: hostname: gateway-9527 client: service-url: register-with-eureka: true fetch-registry: true defaultZone: http://127.0.0.1:8761/eureka
6.啟動類
@SpringBootApplication@EnableDiscoveryClientpublic class GatewayCommonApplication { public static void main(String[] args) { SpringApplication.run(GatewayCommonApplication.class, args); } }
7.測試
2.1 Predicate規(guī)則
上述案例中,我們使用了Gateway中的 Path匹配規(guī)則,也就是根據(jù)請求的uri地址,使用前綴匹配規(guī)則完成請求地址的匹配。
Gateway內(nèi)置了是多種Predicate匹配規(guī)則,具體如下圖所示
2.1.1 Query斷言
Query 路由斷言工廠接收兩個參數(shù),一個必需的參數(shù)和一個可選的正則表達式。
spring: cloud: gateway: routes: – id: query_route uri: https://www.baidu.com/ predicates: – Query=name, eclipse2019.*shuai
如果請求包含一個name的參數(shù),值是eclipse2019開頭,shuaiqi結(jié)尾,則此路由將匹配。第二個參數(shù)是正則表達式。
測試鏈接:http://localhost:9527/?name=feichangshuaiqieclipse2019
2.1.2 Method斷言
Method 路由斷言工廠接收一個參數(shù),即要匹配的 HTTP 方法。
spring: cloud: gateway: routes: – id: method_route uri: https://www.douyu.com/ predicates: – Method=GET
2.1.3 Header斷言
Header 路由斷言工廠接收兩個參數(shù),分別是請求頭名稱和正則表達式。
spring: cloud: gateway: routes: – id: header_route uri: https://www.douyin.com/ predicates: – Header=X-Request-Id, d+
如果請求中帶有請求頭名為 X-Request-Id,其值與 d+ 正則表達式匹配(值為一個或多個數(shù)字),則此路由匹配。
2.1.4 Cookie斷言
spring: cloud: gateway: routes: – id: cookie_route uri: https://www.huya.com/ predicates: – Cookie=name,eclipse2019
通過postman,訪問http://localhost:9527 ; 并且在請求中攜帶cookie name=eclipse2019。 即可匹配到路由進行轉(zhuǎn)發(fā)。
2.2 自定義Predicate
除了使用到官方提供的斷言工廠之外,如果我們有個性化的需求,也是可以實現(xiàn)自定義斷言工廠的。自定義路由斷言工廠需要繼承 AbstractRoutePredicateFactory 類,重寫 apply 方法的邏輯。在 apply 方法中可以通過 exchange.getRequest() 拿到 ServerHttpRequest 對象,從而可以獲取到請求的參數(shù)、請求方式、請求頭等信息。
apply 方法的參數(shù)是自定義的配置類,在使用的時候配置參數(shù),在 apply 方法中直接獲取使用。
命名需要以 RoutePredicateFactory 結(jié)尾,比如 AuthRoutePredicateFactory,那么在使用的時候Auth 就是這個路由斷言工廠的名稱。代碼如下所示。
1.自定義AuthRoutePredicateFactory
@Componentpublic class AuthRoutePredicateFactory extends AbstractRoutePredicateFactory{ Logger logger= LoggerFactory.getLogger(AuthRoutePredicateFactory.class); public static final String NAME_KEY = “name”; public AuthRoutePredicateFactory() { super(Config.class); } @Override public List shortcutFieldOrder() { return Arrays.asList(NAME_KEY); } @Override public Predicate apply(Config config) { logger.info(“AuthRoutePredicateFactory Start”); //只要請求的header中包含yml配置的Authorization,就允許匹配路由 return exchange -> { HttpHeaders headers=exchange.getRequest().getHeaders(); List header=headers.get(config.getName()); return header.size()>0; }; } public static class Config{ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }}
2.在配置文件中添加如下配置信息
– id: define_route uri: https://www.baidu.com predicates: – Path=/define/** – Auth=Authorization filters: – StripPrefix=1
3.訪問測試
第3章 Filter應(yīng)用
filter是網(wǎng)關(guān)中的核心,它起到了請求過濾的作用。在gateway中,會對請求做pre和post的過濾,pre表示請求進來之前,post表示請求處理完成之后返回給客戶端之前。
- pred類型的過濾器可以做授權(quán)認證、流量監(jiān)控、協(xié)議轉(zhuǎn)化等工作
- post過濾器可以做響應(yīng)內(nèi)容的修改、日志的輸出等。
下圖表示的是請求和響應(yīng),經(jīng)過filter的處理流程。
3.1 Filter分類
在Spring Cloud Gateway中,F(xiàn)ilter按照作用范圍可以分為兩類
全局過濾器,針對所有的請求都會被攔截
局部過濾器,只針對某一個指定的route有效
我們先來了解一下局部過濾器,在前面講Predicate的時候,其實已經(jīng)涉及到了Filter的使用。
在Spring Cloud Gateway中,內(nèi)置了非常多的過濾器,如下圖所示
3.2 常用Filter
3.2.1 AddRequestParameter
針對所有匹配的請求,添加一個查詢參數(shù)。
下面這段配置,會針對所有請求增加一個tn=baiduimage&word=%E7%BE%8E%E5%A5%B3的參數(shù)
spring: cloud: gateway: routes: – id: add_request_parameter_route uri: https://image.baidu.com/ predicates: – Path=/search/index/** filters: – AddRequestParameter=tn,baiduimage – AddRequestParameter=word,%E7%BE%8E%E5%A5%B3
3.2.2 RequestRateLimiter
該過濾器會對訪問到當前網(wǎng)關(guān)的所有請求執(zhí)行限流過濾,如果被限流,默認情況下會響應(yīng)HTTP 429-Too Many Requests。RequestRateLimiterGatewayFilterFactory 默認提供了 RedisRateLimiter 的限流實現(xiàn),它采用令牌桶算法來實現(xiàn)限流功能
spring: cloud: gateway: routes: – id: request_ratelimiter_route uri: https://www.taobao.com/ predicates: – Path=/tb/** filters: – StripPrefix=1 – name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 2 redis-rate-limiter.burstCapacity: 5 key-resolver: “#{@userkeyResolver}” #這個必須要配置,否則返回403
redis-rate-limiter 過濾器有兩個配置屬性,如果大家了解令牌桶,就很容易知道它們的含義。
- replenishRate:令牌桶中令牌的填充速度,代表允許每秒執(zhí)行的請求數(shù)。
- burstCapacity:令牌桶的容量,也就是令牌桶最多能夠容納的令牌數(shù)。表示每秒用戶最大能夠執(zhí)行的請求數(shù)量。
- key-resolver:關(guān)鍵字標識的限流
使用redis限流的話還要做一些事:
1.pom中引包
org.springframework.boot spring-boot-starter-data-redis-reactive
2.設(shè)置redis的地址
spring: redis: database: 1 password: eclipse2019 host: localhost
3.在啟動類或者配置類中加如下代碼
@BeanKeyResolver userkeyResolver(){ //根據(jù)請求的ip進行限流 return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());}
3.2.3 Retry
Retry GatewayFilter Factory 為請求重試過濾器,當后端服務(wù)不可用時,網(wǎng)關(guān)會根據(jù)配置參數(shù)來發(fā)起重試請求
spring: cloud: gateway: routes: – id: retry_route uri: http://www.example.com predicates: – Path=/example/** filters: – name: Retry args: retries: 3 status: 503 – StripPrefix=1
RetryGatewayFilter 提供 4 個參數(shù)來控制重試請求,參數(shù)說明如下。
- retries:請求重試次數(shù),默認值是 3。
- status:HTTP 請求返回的狀態(tài)碼,針對指定狀態(tài)碼進行重試,比如,在上述配置中,當服務(wù)端返回的狀態(tài)碼是 503 時,才會發(fā)起重試,此處可以配置多個狀態(tài)碼。
- methods:指定 HTTP 請求中哪些方法類型需要進行重試,默認是 GET。
- series:配置錯誤碼段,表示符合某段狀態(tài)碼才發(fā)起重試,默認值是 SERVER_ERROR(5),表示 5xx 段的狀態(tài)碼都會發(fā)起重試。如果 series 配置了錯誤碼段,但是 status 沒有配置,則仍然會匹配 series 進行重試。
3.2.4 全局過濾器
全局過濾器和GatewayFilter的作用是相同的,只是GlobalFilter針對所有的路由配置生效。Spring Cloud Gateway默認內(nèi)置了一些全局過濾器
- GatewayMetricsFilter,提供監(jiān)控指標。
- ReactiveLoadBalancerClientFilter,整合 Ribbon 針對下游服務(wù)實現(xiàn)負載均衡。
- ForwardRoutingFilter,用于本地 forward,請求不轉(zhuǎn)發(fā)到下游服務(wù)器。
- NettyRoutingFilter,使用 Netty 的 HttpClient 轉(zhuǎn)發(fā) HTTP、HTTPS 請求
- ….
全局過濾鏈的執(zhí)行順序是,當 Gateway 接收到請求時,F(xiàn)iltering Web Handler 處理器會將所有的 GlobalFilter 實例及所有路由上所配置的 GatewayFilter 實例添加到一條過濾器鏈中。該過濾器鏈里的所有過濾器都會按照@Order 注解所指定的數(shù)字大小進行排序。
3.2.5 自定義過濾器
雖然Spring Cloud Gateway提供了非常多的過濾器,但是在實際應(yīng)用中,我們必然會涉及到和業(yè)務(wù)有關(guān)的過濾器,比如日志記錄、鑒權(quán)、黑白名單等。Spring Cloud Gateway 提供了過濾器的擴展功能,開發(fā)者可以根據(jù)實際業(yè)務(wù)需求來自定義過濾器,這樣我們就可以在網(wǎng)關(guān)層實現(xiàn)時鑒權(quán)、日志管理、協(xié)議轉(zhuǎn)化等功能。同樣,自定義過濾器也支持 GlobalFilter 和 GatewayFilter 兩種。
3.2.5.1 自定義GatewayFilter
首先創(chuàng)建一個自定義過濾器類MyDefineGatewayFilterFactory,繼承AbstractGatewayFilterFactory。
@Componentpublic class MyDefineGatewayFilterFactory extends AbstractGatewayFilterFactory{ Logger logger= LoggerFactory.getLogger(MyDefineGatewayFilterFactory.class); public static final String NAME_KEY = “name”; public MyDefineGatewayFilterFactory() { super(MyConfig.class); } @Override public List shortcutFieldOrder() { return Arrays.asList(NAME_KEY); } @Override public GatewayFilter apply(MyConfig config) { return ((exchange, chain) -> { logger.info(“[Pre] Filter Request,name:”+config.getName()); //then接收一個變量,然后then前面處理的那個就結(jié)束了,后面開始處理then接收的這個變量 return chain.filter(exchange).then(Mono.fromRunnable(()->{ logger.info(“[Post] Response Filter”); })); }); } public static class MyConfig{ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }}
在上述代碼中,有幾點需要注意:
- 類名必須要統(tǒng)一以GatewayFilterFactory結(jié)尾,因為默認情況下過濾器的 name 會采用該自定義類的前綴。這里的 name=MyDefine。
- 在apply方法中,同時包含Pre和Post過濾。在then方法中是請求執(zhí)行結(jié)束之后的后置處理。
- MyConfig 是一個配置類,該類中只有一個屬性 name。這個屬性可以在 yml 文件中使用。
- 該類需要裝載到 Spring IoC 容器,此處使用@Component注解實現(xiàn)。
接下來,修改application.yml,增加自定義過濾器配置
spring: cloud: gateway: routes: – id: define_route uri: http://localhost:8080 predicates: – Path=/define/** filters: – MyDefine=My_Eclipse2019
此時訪問到這個過濾器,就會輸出如下日志,說明進入到了網(wǎng)關(guān)攔截器。
2020-06-02 22:08:21.838 INFO 164 — [ioEventLoop-5-2] c.e.s.MyDefineGatewayFilterFactory : [Pre] Filter Request,name:My_Eclipse20192020-06-02 22:08:21.875 INFO 164 — [ctor-http-nio-5] c.e.s.MyDefineGatewayFilterFactory : [Post] Response Filter
3.2.5.2 自定義GlobalFilter
GlobalFilter 的實現(xiàn)比較簡單,它不需要額外的配置,只需要實現(xiàn) GlobalFilter 接口,自動會過濾所有的 Route
@Servicepublic class MyDefineFilter implements GlobalFilter,Ordered{ Logger log= LoggerFactory.getLogger(MyDefineFilter.class); @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { log.info(“[pre]-Enter MyDefineFilter”); return chain.filter(exchange).then(Mono.fromRunnable(()->{ log.info(“[post]-Return Result”); })); } @Override public int getOrder() { return 0; }}
getOrder 表示該過濾器的執(zhí)行順序,值越小,執(zhí)行優(yōu)先級越高。需要注意的是,我們通過 AbstractGatewayFilterFactory 實現(xiàn)的局部過濾器沒有指定 order,它的默認值是 0,如果想要設(shè)置多個過濾器的執(zhí)行順序,可以重寫 getOrder 方法。
第4章 路由
4.1 基于集群負載均衡路由
當被路由的目標服務(wù)是一個集群節(jié)點時,就會涉及到集群路由,Spring Cloud Gateway提供了一個LoadBalancerClientFilter全局過濾器,來實現(xiàn)負載均衡的解析。
1.增加jar包依賴
org.springframework.cloud spring-cloud-starter-netflix-eureka-client
2.user項目也要注冊到Eureka上面去
3.修改application.yml配置
spring: application: name: gateway redis:database: 1 password: eclipse2019 host: localhost cloud: gateway: routes: – id: getUser uri: lb://user # 修改這里 predicates: – Path=/get/** discovery: # 修改這里 locator: enabled: true lower-case-service-id: true server: port: 9527eureka: # 修改這 instance: hostname: gateway-9527 client: service-url: register-with-eureka: true fetch-registry: true defaultZone: http://127.0.0.1:8761/eureka
增加部分的配置說明如下
- lower-case-service-id:是否使用 service-id 的小寫,默認是大寫。
- spring.cloud.gateway.discovery.locator.enabled:開啟從注冊中心動態(tài)創(chuàng)建路由的功能。
- uri 中配置的lb://表示從注冊中心獲取服務(wù),后面的user表示目標服務(wù)在注冊中心上的服務(wù)名
重啟gateway-common項目,訪問:http://localhost/get/3接口。
4.2 動態(tài)路由的實現(xiàn)
在實際應(yīng)用中, 我們還會存在一種:動態(tài)配置路由的需求。也就是在運行過程中,動態(tài)增加或者修改網(wǎng)關(guān)路由配置,這個需求在Spring Cloud Gateway中如何實現(xiàn)呢?
在Spring Cloud Gateway中,提供了GatewayControllerEndpoint這個類來實現(xiàn)路由的動態(tài)修改,可以通過actuator打開這些endpoint信息
1.添加Pom依賴
org.springframework.boot spring-boot-starter-actuator
2.修改application.yml,開發(fā)所有endpoint
management: endpoints: web: exposure: include: *
4.2.1 檢索網(wǎng)關(guān)中定義的路由
通過這個地址:http://localhost:9527/actuator/gateway/routes可以獲得當前網(wǎng)關(guān)中所有定義的路由
[ { predicate: “Paths: [/get/**], match trailing slash: true”, route_id: “getUser”, filters: [ ], uri: “lb://user”, order: 0, }]
其中:
- route_id 表示路由編號
- route_object.predicate 表示路由的條件匹配謂詞
- route_object.filters 表示網(wǎng)關(guān)過濾器
- order 路由順序
4.2.2 查找特定的路由信息。
http://localhost:9527/actuator/gateway/routes/{route_id}
4.2.3 刷新路由緩存
{POST請求}http://localhost:9527/actuator/gateway/refresh
4.2.4 增減、修改路由
/gateway/routes/{id} @PostMapping 新增一個路由信息
/gateway/routes/{id} @DeleteMapping 刪除一個路由信息
1.案例演示(添加路由)
- 通過POST請求添加一個路由信息,http://localhost:9527/actuator/gateway/routes/baidu_route
{ “uri”: “https://www.baidu.com”, “predicates”: [{ “args”: { “pattern”: “/baidu/**” }, “name”: “Path” }], “filters”: [{ “args”: { “_genkey_0”: 1 }, “name”: “StripPrefix” }]}
- 執(zhí)行:{POST請求}http://localhost:9527/actuator/gateway/refresh刷新路由。
- 通過訪問:http://localhost:9527/actuator/gateway/routes 查看當前路由列表,可以發(fā)現(xiàn)多了一個段這樣的內(nèi)容。
{ predicate: “Paths: [/baidu/**], match trailing slash: true”, route_id: “baidu_route”, filters: [ “[[StripPrefix parts = 1], order = 1]” ], uri: “https://www.baidu.com:443”, order: 0,}
- 此時我們訪問: http://localhost:9527/baidu ,就會路由到百度搜索引擎這個網(wǎng)址。
2.案例演示(刪除路由)
- 通過/gateway/routes/{id} @DeleteMapping 刪除一個路由信息
- 通過postman調(diào)用 /gateway/routes/baidu_route (delete請求), 就可以刪除路由,刪除路由之后再次訪問路由列表頁面,此時可以發(fā)現(xiàn)路由信息是被刪除的。
4.2.5 小結(jié)
基于Spring Cloud Gateway默認方法實現(xiàn)的動態(tài)路由就講解完了,但是通過這種形式是去更新的動態(tài)路由信息,是基于內(nèi)存來實現(xiàn)的。一旦服務(wù)重啟,新增的路由配置信息就會全部清空,所以這個時候我們可以參考GatewayControllerEndpoint這個類,來自己實現(xiàn)一套動態(tài)路由的方法。并且將路由信息持久化。
在實際開發(fā)中也可以通過Nacos作為配置中心直接在Nacos上面增加。