我去,你竟然還不會(huì)用API網(wǎng)關(guān)!
原創(chuàng)【51CTO.com原創(chuàng)稿件】從應(yīng)用程序架構(gòu)的變遷過(guò)程可以發(fā)現(xiàn),隨著業(yè)務(wù)多變性、靈活性的不斷提高,應(yīng)用程序需要以更加靈活的組合來(lái)應(yīng)對(duì)。
圖片來(lái)自 Pexels
同時(shí)為了應(yīng)對(duì)業(yè)務(wù)的細(xì)分以及高并發(fā)的挑戰(zhàn),微服務(wù)的架構(gòu)被廣泛使用,由于微服務(wù)架構(gòu)中應(yīng)用會(huì)被拆分成多個(gè)服務(wù)。
為了方便客戶端對(duì)這些服務(wù)的調(diào)用于是引入了 API 的概念。今天我們就來(lái)看看API 網(wǎng)關(guān)的原理以及它是如何應(yīng)用的。
API 網(wǎng)關(guān)的定義
網(wǎng)關(guān)一詞最早出現(xiàn)在網(wǎng)絡(luò)設(shè)備,比如兩個(gè)相互獨(dú)立的局域網(wǎng)之間通過(guò)路由器進(jìn)行通信, 中間的路由被稱之為網(wǎng)關(guān)。
落實(shí)在開發(fā)層面來(lái)說(shuō),就是客戶端與微服務(wù)系統(tǒng)之間存在的網(wǎng)關(guān)。從業(yè)務(wù)層面來(lái)說(shuō),當(dāng)客戶端完成某個(gè)業(yè)務(wù)的時(shí)候,需要同時(shí)調(diào)用多個(gè)微服務(wù)。
如圖 1 所示,當(dāng)客戶端發(fā)起下單請(qǐng)求需要調(diào)用:商品查詢、庫(kù)存扣減以及訂單更新等服務(wù)。
圖1 :API 網(wǎng)關(guān)加入前后對(duì)比
如果這些服務(wù)需要客戶端分別調(diào)用才能完成,會(huì)增加請(qǐng)求的復(fù)雜度,同時(shí)也會(huì)帶來(lái)網(wǎng)絡(luò)調(diào)用性能的損耗。因此,針對(duì)微服務(wù)的應(yīng)用場(chǎng)景就推出了 API 網(wǎng)關(guān)的調(diào)用。
在客戶端與微服務(wù)之間加入下單 API 網(wǎng)關(guān),客戶端直接給這個(gè) API 網(wǎng)關(guān)下達(dá)命令,由于后者完成對(duì)其他三個(gè)微服務(wù)的調(diào)用并且返回結(jié)果給客戶端。
從系統(tǒng)層面來(lái)說(shuō),任何一個(gè)應(yīng)用系統(tǒng)如果需要被其他系統(tǒng)調(diào)用,就需要暴露 API,這些 API 代表著的功能點(diǎn)。
正如上面下單的例子中提到的,如果一個(gè)下單的功能點(diǎn)需要調(diào)用多個(gè)服務(wù)的時(shí)候,在這個(gè)下單的 API 網(wǎng)關(guān)中就需要聚合多個(gè)服務(wù)的調(diào)用。
這個(gè)聚合的方式有點(diǎn)像設(shè)計(jì)模式中的門面模式(Facade),它為外部的調(diào)用提供了一個(gè)統(tǒng)一的訪問(wèn)入口。
不僅如此,如圖 2 所示,API 網(wǎng)關(guān)還可以協(xié)助兩個(gè)系統(tǒng)的通信,在系統(tǒng)之間加上一個(gè)中介者協(xié)助 API 的調(diào)用。
圖 2:對(duì)接兩個(gè)系統(tǒng)的 API 網(wǎng)關(guān)
從客戶端類型層面來(lái)說(shuō),為了屏蔽不同客戶端調(diào)用差異也可以加入 API 網(wǎng)關(guān)。
如圖 3 所示,在實(shí)際開發(fā)過(guò)程中 API 網(wǎng)關(guān)還可以根據(jù)不同的客戶端類型(iOS、Android、PC、小程序),提供不同的 API 網(wǎng)關(guān)與之對(duì)應(yīng)。
圖 3:對(duì)接客戶端和服務(wù)端的 API 網(wǎng)關(guān)
由于 API 網(wǎng)關(guān)所處的位置是客戶端與微服務(wù)交界的地方,因此從功能上它還包括:路由,負(fù)載均衡,限流,緩存,日志,發(fā)布等等。
Spring Cloud Gateway 概念與定義
API 網(wǎng)關(guān)的定義中我們提到了為什么要使用 API 網(wǎng)關(guān),是為了解決客戶端對(duì)多個(gè)微服務(wù)進(jìn)行訪問(wèn)的問(wèn)題。
由于服務(wù)的切分導(dǎo)致一個(gè)操作需要同時(shí)調(diào)用多個(gè)服務(wù),因此為這些服務(wù)的聚合提供一個(gè)統(tǒng)一的門面,這個(gè)門面就是 API 網(wǎng)關(guān)。
針對(duì)于 API 網(wǎng)關(guān)有很多的實(shí)現(xiàn)方式,例如:Zuul,Kong 等等。這里我們以及 Spring Cloud Gateway 為例展開給大家介紹其具體實(shí)現(xiàn)。
一般來(lái)說(shuō),API 網(wǎng)關(guān)對(duì)內(nèi)將微服務(wù)進(jìn)行集合,對(duì)外暴露的統(tǒng)一 URL 或者接口信息供客戶端調(diào)用。
那么客戶端是如何與微服務(wù)進(jìn)行連接,并且進(jìn)行溝通的,需要引入下面幾個(gè)重要概念 。
圖 4:路由、斷言和過(guò)濾器
如圖 4 所示,Spring Cloud Gateway 由三部分組成:
①路由(Route):任何一個(gè)來(lái)自于客戶端的請(qǐng)求都會(huì)經(jīng)過(guò)路由,然后到對(duì)應(yīng)的微服務(wù)中。
每個(gè)路由會(huì)有一個(gè)唯一的 ID 和對(duì)應(yīng)的目的 URL。同時(shí)包含若干個(gè)斷言(Predicate)和過(guò)濾器(Filter)。
②斷言(Predicate):當(dāng)客戶端通過(guò) Http Request 請(qǐng)求進(jìn)入 Spring Cloud Gateway 的時(shí)候,斷言會(huì)根據(jù)配置的路由規(guī)則,對(duì) Http Request 請(qǐng)求進(jìn)行斷言匹配。
說(shuō)白了就是進(jìn)行一次或者多次 if 判斷,如果匹配成功則進(jìn)行下一步處理,否則斷言失敗直接返回錯(cuò)誤信息。
③過(guò)濾器( Filter):簡(jiǎn)單來(lái)說(shuō)就是對(duì)流經(jīng)的請(qǐng)求進(jìn)行過(guò)濾,或者說(shuō)對(duì)其進(jìn)行獲取以及修改的操作。注意過(guò)濾器的功能是雙向的,也就是對(duì)請(qǐng)求和響應(yīng)都會(huì)進(jìn)行修改處理 。
一般來(lái)說(shuō) Spring Cloud Gateway 中的過(guò)濾器有兩種類型:
- Gateway Filter
- Global Filter
Gateway Filter 用在單個(gè)路由和分組路由上。Global Filter 可以作用于所有路由,是一個(gè)全局的 Filter。
Spring Cloud Gateway 工作原理
說(shuō)完了 Spring Cloud Gateway 定義和要素,再來(lái)看看其工作原理。總的來(lái)說(shuō)是對(duì)客戶端請(qǐng)求的處理過(guò)程。
圖 5:Spring Cloud Gateway 處理請(qǐng)求流程圖
如圖 5 所示,當(dāng)客戶端向 Spring Cloud Gateway 發(fā)起請(qǐng)求,該請(qǐng)求會(huì)被 HttpWebHandlerAdapter 獲取,并且對(duì)請(qǐng)求進(jìn)行提取,從而組裝成網(wǎng)關(guān)上下文。
將組成的上下文信息傳遞到 DispatcherHandler 組件。DispatcherHandler 作為請(qǐng)求分發(fā)處理器,主要負(fù)責(zé)將請(qǐng)求分發(fā)到對(duì)應(yīng)的處理器進(jìn)行處理。
這里請(qǐng)求的處理器包括 RoutePredicate HandlerMapping (路由斷言處理映射器) 。
路由斷言處理映射器用于路由的查找,以及找到 路由后返回對(duì)應(yīng)的 FilteringWebHandler。
其負(fù)責(zé)組裝 Filter 鏈表并執(zhí)行過(guò)濾處理,之后再將請(qǐng)求轉(zhuǎn)交給應(yīng)用服務(wù),應(yīng)用服務(wù)處理完后,最后返回 Response 給客戶端 。
其中 FilteringWebHandler 處理請(qǐng)求的時(shí)候會(huì)交給 Filter 進(jìn)行過(guò)濾的處理。
這里需要注意的是由于 Filter 是雙向的所以,當(dāng)客戶端請(qǐng)求服務(wù)的時(shí)候,會(huì)通過(guò) Pre Filter 中的 Filter 處理請(qǐng)求。
當(dāng)服務(wù)處理完請(qǐng)求以后返回客戶端的時(shí)候,會(huì)通過(guò) Post Filter 再進(jìn)行一次處理。
Spring Cloud Gateway 最佳實(shí)踐
上面介紹了 Spring Cloud Gateway 的定義和實(shí)現(xiàn)原理,下面根據(jù)幾個(gè)常用的場(chǎng)景介紹一下 Spring Cloud Gateway 如何實(shí)現(xiàn)網(wǎng)關(guān)功能的。
我們會(huì)根據(jù)基本路由、權(quán)重路由、限流、動(dòng)態(tài)路由幾個(gè)方面給大家展開介紹。
基本路由
基本路由,主要功能就是在客戶端請(qǐng)求的時(shí)候,根據(jù)定義好的路徑指向到對(duì)應(yīng)的 URI。這個(gè)過(guò)程中需要用到 Predicates(斷言)中的 Path 路由斷言處理器。
首先在 POM 文件中加入對(duì)應(yīng)的依賴,如下:
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-gateway</artifactId>
- </dependency>
加入如下代碼,其中定義的 Path 的路徑“/baidu”就是請(qǐng)求時(shí)的路徑地址。對(duì)應(yīng)的 URI,http://www.baidu.com/ 就是要跳轉(zhuǎn)到的目標(biāo)地址。
- @Bean
- public RouteLocator routeLocator(RouteLocatorBuilder builder) {
- return builder.routes()
- .route(r ->r.path("/baidu")
- .uri("http://www.baidu.com/").id("baidu_route")
- ).build();
- }
同樣上面的功能也可以在 yml 文件中實(shí)現(xiàn)。配置文件如下,說(shuō)白了就是對(duì) Path 和 URI 參數(shù)的設(shè)置,實(shí)現(xiàn)的功能和上面代碼保持一致。
- spring:
- cloud:
- gateway:
- routes:
- - id: baidu_route
- uri: http://baidu.com:80/
- predicates:
- - Path=/baidu
此時(shí)啟動(dòng) API 網(wǎng)關(guān),假設(shè)網(wǎng)關(guān)的訪問(wèn)地址是“localhost:8080/baidu”,當(dāng)用戶請(qǐng)求這個(gè)地址的時(shí)候就會(huì)自動(dòng)請(qǐng)求“www.baidu.com”這個(gè)網(wǎng)站。這個(gè)配置起來(lái)很簡(jiǎn)單,有 Nginx 基礎(chǔ)的朋友應(yīng)該很快就能上手。
權(quán)重路由
這個(gè)使用場(chǎng)景相對(duì)于上面的簡(jiǎn)單路由要多一些。由于每個(gè)微服務(wù)發(fā)布新版本的時(shí)候,通常會(huì)保持老版本與新版版同時(shí)存在。
然后通過(guò)網(wǎng)關(guān)將流量逐步從老版本的服務(wù)切換到新版本的服務(wù)。這個(gè)逐步切換的過(guò)程就是常說(shuō)的灰度發(fā)布。
此時(shí),API 網(wǎng)關(guān)就起到了流量分發(fā)的作用,通常來(lái)說(shuō)最開始的老版本會(huì)承載多一些的流量,例如 90% 的請(qǐng)求會(huì)被路由到老版本的服務(wù)上,只有 10% 的請(qǐng)求會(huì)路由到新服務(wù)上去。
從而觀察新服務(wù)的穩(wěn)定性,或者得到用戶的反饋。當(dāng)新服務(wù)穩(wěn)定以后,再將剩下的流量一起導(dǎo)入過(guò)去。
圖 6:灰度發(fā)布,路由到新/老服務(wù)
如下代碼所示,假設(shè) API 網(wǎng)關(guān)還是采用 8080 端口,需要針對(duì)兩個(gè)不同的服務(wù)配置路由權(quán)重。因此在 routes 下面分別配置 service_old 和 service_new。
- server.port: 8080
- spring:
- application:
- name: gateway-test
- cloud:
- gateway:
- routes:
- - id: service_old
- uri: http://localhost:8888/v1
- predicates:
- - Path=/gatewaytest
- - Weight=service, 90
- - id: service_new
- uri: http://localhost:8888/v2
- predicates:
- - Path=/gatewaytest
- - Weight=service, 10
在兩個(gè)配置中對(duì)應(yīng)的 URI 分別是新老兩個(gè)服務(wù)的訪問(wèn)地址,通過(guò)“http://localhost:8888/v1”和“http://localhost:8888/v2”來(lái)區(qū)別。
在 Predicates(斷言)中定義了的 Path 是想通的都是“/gatewaytest”,也就是說(shuō)對(duì)于客戶端來(lái)說(shuō)訪問(wèn)的路徑都是一樣的,從路徑上客戶不會(huì)感知他們?cè)L問(wèn)的是新服務(wù)或者是老服務(wù)。
主要參數(shù)是在 Weight,針對(duì)老/新服務(wù)分別配置的是 90 和 10。也就是有 90% 的流量會(huì)請(qǐng)求老服務(wù),有 10% 的流量會(huì)請(qǐng)求新服務(wù)。
簡(jiǎn)單點(diǎn)說(shuō),如果有 100 次請(qǐng)求,其中 90 次會(huì)請(qǐng)求 v1(老服務(wù)),另外的 10 次會(huì)請(qǐng)求 v2(新服務(wù))。
限流
當(dāng)服務(wù)在短時(shí)間內(nèi)迎來(lái)高并發(fā),并發(fā)量超過(guò)服務(wù)承受的范圍就需要使用限流。例如:秒殺、搶購(gòu)、下單服務(wù)。
通過(guò)請(qǐng)求限速或者對(duì)一個(gè)時(shí)間窗口內(nèi)的請(qǐng)求進(jìn)行限速來(lái)保護(hù)服務(wù)。當(dāng)達(dá)到限制速率則可以拒絕請(qǐng)求,返回錯(cuò)誤代碼,或者定向到友好頁(yè)面。
一般的中間件都會(huì)有單機(jī)限流框架,支持兩種限流模式:
- 控制速率
- 控制并發(fā)
這里通過(guò) Guava 中的 Bucket4j 來(lái)實(shí)現(xiàn)限流操作。按照慣例引入 Bucket4j 的依賴:
- <dependency>
- <groupId>com.github.vladimir-bukhtoyarov</groupId>
- <artifactId>bucket4j-core</artifactId>
- <version>4.0.0</version>
- </dependency>
由于需要對(duì)于用戶請(qǐng)求進(jìn)行監(jiān)控,因此通過(guò)實(shí)現(xiàn) GatewayFilter 的方式自定義 Filter,然后再通過(guò) Gateway API Application 應(yīng)用這個(gè)自定義的 Filter。
這里我們使用的是令牌桶的方式進(jìn)行限流,因此需要設(shè)置桶的容量(capacity),每次填充的令牌數(shù)量(refillTokens)以及填充令牌的間隔時(shí)間(refillDuration)。
初始化這三個(gè)參數(shù)以后,通過(guò) createNewBucket 方法針對(duì)請(qǐng)求建立令牌桶(bucket),在 Filter 方法中實(shí)現(xiàn)限流的主要邏輯。
通過(guò) ServerWebExchange 獲取請(qǐng)求的上下文中的 IP 信息,針對(duì) IP 建立對(duì)應(yīng)的令牌桶,這個(gè) IP 與令牌桶的對(duì)應(yīng)關(guān)系放到了 LOCAL_CACHE 中。
每次請(qǐng)求經(jīng)過(guò)的時(shí)候通過(guò) tryConsume(1) 方法消費(fèi)一個(gè)令牌,直到?jīng)]有令牌的時(shí)候返回 HttpStatus.TOO_MANY_REQUESTS 的狀態(tài)碼(429),此時(shí)網(wǎng)關(guān)直接返回請(qǐng)求次數(shù)太多,即便是再有請(qǐng)求進(jìn)來(lái)也不會(huì)路由到對(duì)應(yīng)的服務(wù)了。
只有等待下一個(gè)時(shí)間間隔,一定數(shù)量的令牌放到桶里的時(shí)候,請(qǐng)求拿到桶中的令牌才能再次請(qǐng)求服務(wù)。
- public class GatewayRateLimitFilterByIp implements GatewayFilter, Ordered {
- private static final Map<String, Bucket> LOCAL_CACHE = new ConcurrentHashMap<>();
- int capacity;
- int refillTokens;
- Duration refillDuration;
- public GatewayRateLimitFilterByIp() {
- }
- public GatewayRateLimitFilterByIp(int capacity, int refillTokens, Duration refillDuration) {
- this.capacity = capacity;
- this.refillTokens = refillTokens;
- this.refillDuration = refillDuration;
- }
- private Bucket createNewBucket() {
- Refill refill = Refill.of(refillTokens, refillDuration);
- Bandwidth limit = Bandwidth.classic(capacity, refill);
- return Bucket4j.builder().addLimit(limit).build();
- }
- @Override
- public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
- String ip = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
- Bucket bucket = LOCAL_CACHE.computeIfAbsent(ip, k -> createNewBucket());
- if (bucket.tryConsume(1)) {
- return chain.filter(exchange);
- } else {
- exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
- return exchange.getResponse().setComplete();
- }
- }
- }
上面的代碼定義了 Filter 其中針對(duì)訪問(wèn)的 IP 生成令牌桶,并且定義了桶的大小、每次放入桶令牌的個(gè)數(shù)、放入令牌的間隔時(shí)間。
并且通過(guò) Filter 方法重寫了過(guò)濾的邏輯,那么下面只需要將這個(gè) Filter 應(yīng)用到 Spring Cloud Gateway 的規(guī)則上去就可以了。通過(guò)下面代碼定義網(wǎng)關(guān)的路由斷言和過(guò)濾器。
在 Filters 中新建一個(gè)上面代碼定義的過(guò)濾器,指定容量是 20,每?jī)擅敕湃肓钆疲看畏湃胍粋€(gè)令牌。
那么當(dāng)用戶訪問(wèn) rateLimit 路徑的時(shí)候就會(huì)根據(jù)客制化的 Filter 進(jìn)行限流。
- @Bean
- public RouteLocator testRouteLocator(RouteLocatorBuilder builder) {
- return builder.routes()
- .route(r -> r.path("/rateLimit")
- .filters(f -> f.filter(new GatewayRateLimitFilterByIp(20,1,Duration.ofSeconds(2))))
- .uri("http://localhost:8888/rateLimit")
- .id("rateLimit_route")
- ).build();
- }
這里的限流只是給大家提供一種思路,通過(guò)實(shí)現(xiàn) GatewayFilter,重寫其中的 Filter 方法,加入對(duì)流量的控制代碼,然后在 Spring Cloud Gateway 中進(jìn)行應(yīng)用就可以了。
動(dòng)態(tài)路由
由于 Spring Cloud Gateway 本身也是一個(gè)服務(wù),一旦啟動(dòng)以后路由配置就無(wú)法修改了。
無(wú)論是上面提到的編碼注入的方式還是配置的方式,如果需要修改都需要重新啟動(dòng)服務(wù)。
如果回到 Spring Cloud Gateway 最初的定義,我們會(huì)發(fā)現(xiàn)每個(gè)用戶的請(qǐng)求都是通過(guò) Route 訪問(wèn)對(duì)應(yīng)的微服務(wù),在 Route 中包括 Predicates 和 Filters 的定義。
只要實(shí)現(xiàn) Route 以及其包含的 Predicates 和 Filters 的定義,然后再提供一個(gè) API 接口去更新這個(gè)定義就可以動(dòng)態(tài)地修改路由信息了。
按照這個(gè)思路需要做以下幾步來(lái)實(shí)現(xiàn):
①定義 Route、Predicates 和 Filters
其中 Predicates 和 Filters 包含在 Route 中。實(shí)際上就是 Route 實(shí)體的定義,針對(duì) Route 進(jìn)行路由規(guī)則的配置。
- public class FilterDefinition {
- //Filter Name
- private String name;
- //對(duì)應(yīng)的路由規(guī)則
- private Map<String, String> args = new LinkedHashMap<>();
- }
- public class PredicateDefinition {
- //Predicate Name
- private String name;
- //對(duì)應(yīng)的斷言規(guī)則
- private Map<String, String> args = new LinkedHashMap<>();
- }
- public class RouteDefinition {
- //斷言集合
- private List<PredicateDefinition> predicates = new ArrayList<>();
- //路由集合
- private List< FilterDefinition > filters= new ArrayList<>();
- //uri
- private String uri;
- //執(zhí)行次序
- private int order = 0;
- }
②實(shí)現(xiàn)路由規(guī)則的操作,包括添加,更新,刪除
有了路由的定義(Route,Predicates,F(xiàn)ilters),然后再編寫針對(duì)路由定義的操作。
例如:添加路由,刪除路由,更新路由之類的。編寫 RouteServiceImpl 實(shí)現(xiàn) ApplicationEventPublisherAware。
主要需要 override 其中的 setApplicationEventPublisher 方法,這里會(huì)傳入 ApplicationEventPublisher 對(duì)象,通過(guò)這個(gè)對(duì)象發(fā)布路由定義的事件包括:add,update,delete。
貼出部分代碼如下:
- @Service
- public class RouteServiceImpl implements ApplicationEventPublisherAware {
- @Autowired
- private RouteDefinitionWriter routeDefinitionWriter;
- private ApplicationEventPublisher publisher;
- //添加路由規(guī)則
- public String add(RouteDefinition definition) {
- routeDefinitionWriter.save(Mono.just(definition)).subscribe();
- this.publisher.publishEvent(new RefreshRoutesEvent(this));
- return "success";
- }
- public String update(RouteDefinition definition) {
- try {
- this.routeDefinitionWriter.delete(Mono.just(definition.getId()));
- } catch (Exception e) {
- }
- try {
- routeDefinitionWriter.save(Mono.just(definition)).subscribe();
- this.publisher.publishEvent(new RefreshRoutesEvent(this));
- return "success";
- } catch (Exception e) {
- }
- }
- public String delete(String id) {
- try {
- this.routeDefinitionWriter.delete(Mono.just(id));
- return "delete success";
- } catch (Exception e) {
- }
- }
- @Override
- public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
- this.publisher = applicationEventPublisher;
- }
③對(duì)外部提供 API 接口能夠讓用戶或者程序動(dòng)態(tài)修改路由規(guī)則
從代碼上來(lái)說(shuō)就是一個(gè) Controller。這個(gè) Controller 中只需要調(diào)用 routeServiceImpl 就行了,主要也是用到客制化路由實(shí)現(xiàn)類中的 add,update,delete 方法。
說(shuō)白了就是對(duì)其進(jìn)行了一次包裝,讓外部系統(tǒng)可以調(diào)用,并且修改路由的配置。
經(jīng)過(guò)簡(jiǎn)化以后的代碼如下,這里只對(duì) add 方法進(jìn)行了包裝,關(guān)于 update 和 delete 方法在這里不展開說(shuō)明,調(diào)用方式類似 add。
- public class RouteController {
- @Autowired
- private routeServiceImpl routeService;
- @PostMapping("/add")
- public String add(@RequestBody RouteDefinition routeDefinition) {
- try {
- RouteDefinition definition = assembleRouteDefinition(routeDefinition);
- return this.dynamicRouteService.add(definition);
- } catch (Exception e) {
- }
- return "succss";
- }
- }
④啟動(dòng)程序進(jìn)行路由的添加和更新操作
假設(shè)更新 API 網(wǎng)關(guān)配置的服務(wù)在 8888 端口上。于是通過(guò) http://localhost:8888/actuator/gateway/routes 訪問(wèn)當(dāng)前的路由信息,由于現(xiàn)在沒(méi)有配置路由這個(gè)信息是空。
那么通過(guò) http://localhost:8888/route/add 方式添加一條路由規(guī)則,這里選擇 Post 請(qǐng)求,輸入類型為 Json 如下:
- {
- "filter":[],
- "id":"baidu_route",
- "order":0,
- "predicates":[{
- "args":{
- "pattern":"/baidu"
- },
- "name":"Path"
- }],
- "uri":"https://www.baidu.com"
- }
Json 中配置的內(nèi)容和簡(jiǎn)單路由配置的內(nèi)容非常相似。設(shè)置了 Route,當(dāng) Predicates 為 baidu 的時(shí)候,將請(qǐng)求引導(dǎo)到 www.baidu.com 的網(wǎng)站進(jìn)行響應(yīng)。
此時(shí)再通過(guò)訪問(wèn) http://localhost:8888/baidu 的路徑訪問(wèn)的時(shí)候,就會(huì)被路由到 www.baidu.com 的網(wǎng)站。
此時(shí)如果需要修改路由配置,可以通過(guò)訪問(wèn) http://localhost:8888/route/update 的 API 接口,通過(guò) Post 方式傳入 Json 結(jié)構(gòu),例如:
- {
- "filter":[],
- "id":"CTO_route",
- "order":0,
- "predicates":[{
- "args":{
- "pattern":"/CTO"
- },
- "name":"Path"
- }],
- "uri":"http://www.ekrvqnd.cn"
- }
在更新完成以后,再訪問(wèn) http://localhost:8888/CTO 的時(shí)候就會(huì)把引導(dǎo)到 www.ekrvqnd.cn 的網(wǎng)站了。
通過(guò)上面四步操作,即使不重啟 Spring Cloud Gateway 服務(wù)也可以動(dòng)態(tài)更改路由的配置信息。
總結(jié)
由于微服務(wù)的盛行,API 網(wǎng)關(guān)悄然興起。針對(duì) API 網(wǎng)關(guān)本身講述了其存在的原因,它不僅提供了服務(wù)的門面,而且可以協(xié)調(diào)不同的系統(tǒng)之間的通訊以及服務(wù)不同的客戶端接口。
針對(duì) API 網(wǎng)關(guān)的最佳時(shí)間 Spring Cloud Gateway 的定義和概念的解釋,其實(shí)現(xiàn)了路由、過(guò)濾器、斷言,針對(duì)不同的客戶端請(qǐng)求可以路由到不同的微服務(wù),以及其中幾個(gè)組件是如何分工合作完成路由工作的。
在最佳實(shí)踐的介紹中分別從:基本路由、權(quán)重路由、限流和動(dòng)態(tài)路由幾個(gè)方面進(jìn)行了闡述。
【51CTO原創(chuàng)稿件,合作站點(diǎn)轉(zhuǎn)載請(qǐng)注明原文作者和出處為51CTO.com】