《吃透微服務(wù)》 - 服務(wù)網(wǎng)關(guān)之Gateway
大家好,我是小菜。
一個希望能夠成為 吹著牛X談架構(gòu) 的男人!如果你也想成為我想成為的人,不然點個關(guān)注做個伴,讓小菜不再孤單!
本文主要介紹
SpringCloud之服務(wù)網(wǎng)關(guān)Gateway如有需要,可以參考
如有幫助,不忘 點贊 ?
微信公眾號已開啟,小菜良記,沒關(guān)注的同學(xué)們記得關(guān)注哦!
前段時間與小伙伴閑聊時說到他們公司的現(xiàn)狀,近來與將來,公司將全面把單體服務(wù)向微服務(wù)架構(gòu)過渡。這里面我們聽到了關(guān)鍵詞 --- 微服務(wù)。乍聽之下,覺得也很合理。互聯(lián)網(wǎng)在不斷的發(fā)展,這里不只是行業(yè)的發(fā)展,更是系統(tǒng)架構(gòu)的發(fā)展。現(xiàn)在市面上架構(gòu)大致也經(jīng)歷了這幾個階段:

這是好事嗎?是好事,毋庸置疑。因為不跟上時代的浪潮,總會被拍死在沙灘上。但完全是好事嗎?那也不見得。
我們先要明白微服務(wù)解決了什么問題?大方面上應(yīng)該就是應(yīng)用層面和人層面的問題
應(yīng)用層面: 單體服務(wù)的架構(gòu)很簡單,項目開發(fā)和維護成本低是它無爭議的優(yōu)點。但是臃腫耦合又會給基礎(chǔ)設(shè)施帶來了過重的負擔(dān)。如果某個應(yīng)用處理資源占用了大量的CPU,就會導(dǎo)致其他處理資源餓死的現(xiàn)象,系統(tǒng)延遲增高,直接影響系統(tǒng)的可用性。
人層面:
獨立、多語言生態(tài)也是微服務(wù)的標簽。在單體服務(wù)中,投入的人力資源越多不見得越高效,反而越容易出錯。但微服務(wù)不同,每個服務(wù)都是獨立出來的,團隊可以更加容易的協(xié)作開發(fā),甚至一套系統(tǒng),多個服務(wù),多種語言,毫無沖突。

但是我們凡事不能被好處蒙蔽。微服務(wù)的缺點也是一直存在的:
- 需要考慮各個服務(wù)之間的容錯性問題
- 需要考慮數(shù)據(jù)一致性問題
- 需要考慮分布式事務(wù)問題
- ...
很多人認為微服務(wù)的核心就是在于 微。服務(wù)分的越細越好,就好像平時寫代碼的時候絲毫不考慮的單一原則,反而在服務(wù)拆分上用到淋漓盡致。這里就需要明白一個核心概念:微服務(wù)的關(guān)鍵不在微,而是在于合適的大小
這句話好像很簡單的樣子,但是多大才算合適的大小?這可能據(jù)不同團隊,不同項目而定。合適的大小可能取決于更少的代碼倉庫,更少的部署隊列,更少的語言... 這里更無法一錘定音!
如果沒法做到合適的大小,而無腦的拆分服務(wù),那么微服務(wù)可能反而成為你項目的累贅。因此,有時全面轉(zhuǎn)型微服務(wù)反而不是好事,你覺得呢?
話題有點跑遠了,咱們努力扯回來。既然微服務(wù)已經(jīng)成為主流,那么如何設(shè)計微服務(wù)便是我們應(yīng)該做的事,而不是談及微服務(wù)之時,想到的只是與人如何爭論如何拒用微服務(wù)。那么這篇我們要講的是SpringCloud之服務(wù)網(wǎng)關(guān)Gateway
SpringCloud之服務(wù)網(wǎng)關(guān)Gateway
一、認識網(wǎng)關(guān)
什么是服務(wù)網(wǎng)關(guān)?不要給自己當(dāng)頭一棒。我們換個問法,為什么需要服務(wù)網(wǎng)關(guān)?
服務(wù)網(wǎng)關(guān)是跨一個或多個服務(wù)節(jié)點提供單個統(tǒng)一的訪問入口
它的作用并不是可有可無的存在,而是至關(guān)重要。我們可以在服務(wù)網(wǎng)關(guān)做路由轉(zhuǎn)發(fā)和過濾器的實現(xiàn)。優(yōu)點簡述如下:
- 防止內(nèi)部服務(wù)關(guān)注暴露給外部客戶端
- 為我們內(nèi)部多個服務(wù)添加了額外的安全層
- 減低微服務(wù)訪問的復(fù)雜性

根據(jù)圖中內(nèi)容,我們可以得出以下信息:
- 用戶訪問入口,統(tǒng)一通過網(wǎng)關(guān)訪問到其他微服務(wù)節(jié)點
- 服務(wù)網(wǎng)關(guān)的功能有
路由轉(zhuǎn)發(fā),API監(jiān)控、權(quán)限控制、限流
而這些便是 服務(wù)網(wǎng)關(guān) 存在的意義!
1)Zuul 比較
SpringCloud Gateway 是 SpringCloud 的一個全新項目,目標是取代Netflix Zuul。它是基于 Spring5.0 + SpringBoot2.0 + WebFlux 等技術(shù)開發(fā)的,性能高于 Zuul,據(jù)官方提供的信息來看,性能是 Zuul 的1.6倍,意在為微服務(wù)架構(gòu)提供一種簡單有效的統(tǒng)一的 API 路由管理方式。
SpringCloud Gateway 不僅提供了統(tǒng)一的路由方式(反向代理),并且基于 Filter 鏈(定義過濾器對請求過濾)提供了網(wǎng)關(guān)基本的功能,例如:鑒權(quán)、流量控制、熔斷、路徑重寫、日志監(jiān)控等。
其實說到 Netflix Zuul,在使用或準備使用微服務(wù)架構(gòu)的小伙伴應(yīng)該并不陌生,畢竟Netflix 是一個老牌微服務(wù)開源者。新秀與老牌之間的爭奪,如果新秀沒有點硬實力,如何讓人安心轉(zhuǎn)型!
這里我們可以順帶了解一下 Weflux,Webflux 的出現(xiàn)填補了 Spring 在響應(yīng)式編程上的空白。
可能有很多小伙伴并不知道 Webflux,小菜接下來也會出一篇關(guān)于 Webflux 的講解,實則真香!
Webflux 的響應(yīng)式編程不僅僅是編程風(fēng)格上的改變,而是對于一系列著名的框架都提供了響應(yīng)式訪問的開發(fā)包,比如 Netty、Redis(如果不知道 Netty 的實力,可以想想為什么 Nginx 可以承載那么大的并發(fā),底層就是基于Netty)
那么說這么多,跟 Zuul 有什么關(guān)系呢?我們可以看下 Zuul 的 IO 模型
SpringCloud 中所集成的 Zuul 版本,采用的是 Tomcat 容器,使用的是傳統(tǒng)的 Servlet IO 處理模型。Servlet 是由 Servlet Container 管理生命周期的。

但問題就在于 Servlet 是一個簡單的網(wǎng)絡(luò)IO模型,當(dāng)請求進入到 ServletContainer就會為其綁定一個線程,在并發(fā)不高的場景下這種模型是沒有問題的,但是一旦并發(fā)上來了,線程數(shù)量就會增加。那導(dǎo)致的問題就是頻繁進行上下文切換,內(nèi)存消耗嚴重,處理請求的時間就會變長。正所謂牽一發(fā)而動全身!
而 SpriingCloud Zuul 便是基于 servlet 之上的一個阻塞式處理模型,即Spring實現(xiàn)了處理所有 request 請求的一個 servlet(DispatcherServlet),并由該 Servlet 阻塞式處理。雖然 SpringCloud Zuul 2.0 開始,也是用了 Netty 作為并發(fā)IO框架,但是 SpringCloud 官方已經(jīng)沒有集成該版本的計劃!
注:這里沒有推崇 Gateway 的意思,具體使用依具體項目而定
三、掌握網(wǎng)關(guān)
1. Gateway 依賴
最關(guān)鍵的一步便是引入網(wǎng)關(guān)的依賴
<!--gateway網(wǎng)關(guān)-->
<dependency>
????<groupId>org.springframework.cloud</groupId>
????<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
2. 項目結(jié)構(gòu)

我這里簡單的創(chuàng)建了一個微服務(wù)項目,項目里有一個 store-gateway 服務(wù)網(wǎng)關(guān) 和一個 store-order 訂單服務(wù)。因為我們這篇只說明服務(wù)網(wǎng)關(guān)的作用,不需要太多服務(wù)提供者和消費者!
在store-order訂單服務(wù)中只有一個控制器OrderController,里面也只有一個簡單到發(fā)指的API
@RestController
@RequestMapping("order")
public?class?OrderController?{
????
????@GetMapping("/{id:.+}")
????public?String?detail(@PathVariable?String?id)?{
????????return?StringUtils.join("獲取到了ID為",?id,?"的商品");
????}
????
}
我們分別啟動兩個服務(wù),然后訪問訂單服務(wù)的API:

結(jié)果肯定是符合預(yù)期的,不至于翻車。8001 是訂單服務(wù)的接口,這個時候我們可以了解到,原來微服務(wù)架構(gòu)每個服務(wù)獨立啟動,都是可以獨立訪問的,也就相當(dāng)于傳統(tǒng)的單體服務(wù)。
我們想想看,如果用端口來區(qū)分每個服務(wù),是否也可以達到微服務(wù)的效果?理論上好像是可以的,但是如果成百上千個服務(wù)呢?端口爆炸,維護爆炸,治理爆炸... 不說別的,心態(tài)直接爆炸了!這個時候我們就想著如果只用統(tǒng)一的一個端口訪問各個服務(wù),那該多好!端口一致,路由前綴不一致,通過路由前綴來區(qū)分服務(wù),這種方式將我們帶入了服務(wù)網(wǎng)關(guān)的場景。是的,這里就說到了服務(wù)網(wǎng)關(guān)的功能之一 --- 路由轉(zhuǎn)發(fā)。
3. 網(wǎng)關(guān)出現(xiàn)
既然要用到網(wǎng)關(guān),那我們上面創(chuàng)建的服務(wù)之一 store-gateway 就派上用場了!怎么用?我們在配置文件做個簡單的修改:
spring:
??application:
????name:?store-gateway
??cloud:
????gateway:
??????routes:?
????????-?id:?store-order?
??????????uri:?http://localhost:8001?
??????????order:?1
??????????predicates:
????????????-?Path=/store-order/**?
??????????filters:
????????????-?StripPrefix=1
不多廢話,我們直接啟動網(wǎng)關(guān),通過訪問http://localhost:8000/store-order/order/123 看是否能獲取到訂單?

很順利,我們成功拿到了ID 為 123 的訂單商品!
我們看下 URL 的組成:

能夠訪問到我們的服務(wù),說明網(wǎng)關(guān)配置生效了,我們再來看下這么配置項是怎么一回事!
spring.cloud.gateway 這個是服務(wù)網(wǎng)關(guān) Gateway 的配置前綴,沒什么好說的,自己需要記住就是了。
routes 以下就是我們值得關(guān)注的了,routes 是個復(fù)數(shù)形式,那么可以肯定,這個配置項是個數(shù)組的形式,因此意味著我們可以配多個路由轉(zhuǎn)發(fā),當(dāng)請求滿足什么條件的時候轉(zhuǎn)到哪個微服務(wù)上。
- id: 當(dāng)前路由的
唯一標識 - uri: 請求要轉(zhuǎn)發(fā)到的地址
- order:路由的優(yōu)先級,數(shù)字越小級別越高
- predicates: 路由需要滿足的條件,也是個數(shù)組(這里是
或的關(guān)系) - filters: 過濾器,請求在傳遞過程中可以通過過濾器對其進行一定的修改
了解完必要的參數(shù),我們也高高興興去部署使用了,但是好景不長,我們又迎來了新的問題。我訂單服務(wù)原先使用的 8001 端口,因為某些原因給其他服務(wù)使用了,這個時候小腦袋又大了,這種情況肯定不會出現(xiàn) 上錯花轎嫁對郎 的結(jié)果!
咱們想想看這種問題要怎么解決比較合適?既然都采用微服務(wù)了,那我們能不能采用服務(wù)名的方式跳轉(zhuǎn)訪問,這樣子無論端口怎么變,都不會影響到我們的正常業(yè)務(wù)!那如果采用服務(wù)的方式,就需要一個注冊中心,這樣子我們啟動的服務(wù)可以同步到注冊中心的 注冊表 中,這樣子網(wǎng)關(guān)就可以根據(jù) 服務(wù)名 去注冊中心中尋找服務(wù)進行路由跳轉(zhuǎn)了!那咱們就需要一個注冊中心,這里就采用 Nacos 作為注冊中心.
關(guān)于 Nacos 的了解,可以空降 微服務(wù)新秀之Nacos,看了就會,我說的!
我們分別在服務(wù)網(wǎng)關(guān) 和 訂單服務(wù)的配置文件都做了以下配置:

啟動兩個服務(wù)后,我們可以在 Nacos 的控制臺服務(wù)列表中看到兩個服務(wù):

這個時候可以看到 訂單服務(wù) 的服務(wù)名為:store-order,那我們就可以在網(wǎng)關(guān)配置文件部分做以下修改:

這里的配置與上述不同點之一 http 換成了 lb(lb 指的是從nacos中按照名稱獲取微服務(wù),并遵循負載均衡策略),之二 端口 換成了 服務(wù)名
那我們繼續(xù)訪問上述URL看是否能夠成功訪問到訂單服務(wù):

結(jié)果依然沒有翻車!這樣子,不管訂單服務(wù)的端口如何改變,只要我們的服務(wù)名不變,那么始終都可以訪問到我們的對應(yīng)的服務(wù)!
日子一天一天的過去~ 服務(wù)也一點一點的增加!終于有一天小菜煩了,因為每次增加服務(wù)都得去配置文件中增加一個routes 的配置列,雖然也只是 CV 的操作,但是,哪一天小菜不小心手一抖,那么~~~ 算了算了,找找看有沒有什么可以偷懶的寫法,終于不負小菜心,找到了一種簡化版!配置如下:

就這?是的,就這!管你服務(wù)再怎么多,我配置文件都不用修改。這樣子配置的目的便是請求統(tǒng)一方式都是變成了 網(wǎng)關(guān)地址:網(wǎng)關(guān)端口/服務(wù)名/接口名 的方式訪問。再次訪問頁面,依然行得通!

但是方便歸方便,在方便的同時也限制了很多擴展功能,因此使用需三思!不可貪懶!
四、掌握核心
上面已經(jīng)說完了網(wǎng)關(guān)的簡單使用,看完的小伙伴肯定已經(jīng)可以上手了!接下來我們繼續(xù)趁熱打鐵,了解下 Gateway 網(wǎng)關(guān)的核心。不說別的,路由轉(zhuǎn)發(fā) ?肯定是網(wǎng)關(guān)的核心!我們從上面已經(jīng)了解到一個具體路由信息載體,主要定義了以下幾個信息(回憶下):
id: 路由的唯一標識,區(qū)別于其他Route
uri: 路由指向目的地 uri,即客戶端請求最終被轉(zhuǎn)發(fā)到的微服務(wù)
order: 用于多個 Route 之間的排序,數(shù)值越小排序越靠前,匹配優(yōu)先級越高
predicate: 用來進行條件判斷,只有斷言都返回真,才會真正的執(zhí)行路由
filter: 過濾器用于修改請求和響應(yīng)信息
這里來梳理一下訪問流程:

這張圖很清楚的描述服務(wù)網(wǎng)關(guān)的調(diào)用流程(盲目自信)
- GatewayClient 向 GatewayServer 發(fā)出請求
- 請求首先會被 HttpWebHandlerAdapter 進行提取組轉(zhuǎn)成網(wǎng)關(guān)上下文
- 然后網(wǎng)關(guān)的上下文會傳遞到 DispatcherHandler,它負責(zé)將請求分發(fā)給 RoutePredicateHandlerMapping
- RoutePredicateHandlerMapping負責(zé)路由查找,并更具路由斷言判斷路由是否可用
- 如果斷言成功,由 FilteringWebHandler 創(chuàng)建過濾器鏈并調(diào)用
- 請求會一次經(jīng)過 PreFilter ---> 微服務(wù) ---> PostFilter 的方法,最終返回響應(yīng)
過程了解了,我們抽取一下其中的關(guān)鍵!斷言 和 過濾器
1. ?斷言
Predicate 也就是斷言,主要適用于進行條件判斷,只有斷言都返回真,才會真正執(zhí)行路由
1)斷言工廠
SpringCloud Gateway 中內(nèi)置了許多斷言工廠,所有的這些斷言都和 HTTP 請求不同的屬性相匹配,具體如下;
- 基于 Datetime 類型的斷言工廠
該類型的斷言工廠是根據(jù)時間做判斷的
1、AfterRoutePredicateFactory: 接收一個日期參數(shù),判斷請求日期是否晚于指定日期
2、**BeforeRoutePredicateFactory:**接收一個日期參數(shù),判斷請求日期是否早于指定日期
3、**BetweenRoutePredicateFactory:**接收兩個日期參數(shù),判斷請求日期是否在指定時間段內(nèi)
- 基于遠程地址的斷言工廠 RemoteAddrRoutePredicateFactory
該類型的斷言工廠是接收一個參數(shù),IP 地址端,判斷請求主機地址是否在地址段中。(eq:-RemoteAddr=192.168.1.1/24)
- 基于Cookie的斷言工廠 CookieRoutePredicateFactory
該類型的斷言工廠接收兩個參數(shù),Cookie 名字和一個正則表達式,判斷請求 cookie 是否具有給定名稱且值與正則表達式匹配。(eq:-Cookie=cbuc)
- 基于Header的斷言工廠HeaderRoutePredicateFactory
該類型的斷言工廠接收兩個參數(shù),標題名稱和正則表達式。判斷請求 Header 是否具有給定名稱且值與正則表達式匹配。(eq:-Header=X-Request)
- 基于Host的斷言工廠 HostRoutePredicateFactory
該類型的斷言工廠接收一個參數(shù),主機名模式。判斷請求的host 是否滿足匹配規(guī)則。(eq:-Host=**.cbuc.cn)
- 基于Method請求方法的斷言工廠 MethodRoutePredicateFactory
該類型的斷言工廠接收一個參數(shù),判斷請求類型是否跟指定的類型匹配。(eq:-Method=GET)
- 基于Path請求路徑的斷言工廠 PathRoutePredicateFactory
該類型的斷言工廠接收一個參數(shù),判斷請求的URI部分是否滿足路徑規(guī)則。(-eq:-Path=/order/)
- 基于Query請求參數(shù)的斷言工廠 QueryRoutePredicateFactory
該類型的斷言工廠接收兩個參數(shù),請求 Param 和 正則表達式。判斷請求參數(shù)是否具有給定名稱且值與正則表達式匹配。(eq:-Query=cbuc)
- 基于路由權(quán)重的斷言工廠 WeightRoutePredicateFactory
該類型的斷言工廠接收一個[組名,權(quán)重],然后對于同一個組內(nèi)的路由按照權(quán)重轉(zhuǎn)發(fā)
2)使用
這么多斷言工廠,這里就不一一使用演示了,我們結(jié)合幾個斷言工廠的使用演示一下。
我們老樣子不多廢話,直接上代碼:
CustomPredicateRouteFactory

配置文件

測試結(jié)果
success

fail

驚呼 Amazing 的同時,不要著急的往下看,我們回歸代碼,看看,為什么一個可以訪問成功,一個卻訪問失敗了。兩個方面:1. 兩者訪問的URL有哪些不同 2. 代碼哪部分對 URL 做出了處理
先養(yǎng)成獨立思考,再去看解決方法
當(dāng)你思考完后,可能部分同學(xué)已經(jīng)有結(jié)果了,那讓我們繼續(xù)往下看!首先是一個 CustomRoutePredicateFactory類,這個類的作用有點像攔截器,在做請求轉(zhuǎn)發(fā)的時候進行了攔截,我們請求的時候可以打個斷點:

可以看到,確實是攔截器的功能,在每個請求發(fā)起的時候做了攔截。那問題2 的結(jié)果就出來了,原來URL處理是在 RoutePredicateFactory 中做了處理,在 apply 方法中可以通過 exchange.getRequest() 拿到 ServerHttpRequest 對象,從而可以獲取到請求的參數(shù)、請求方式、請求頭等信息。shortcutFieldOrder()方法也是重寫的關(guān)鍵之一,我們需要這里返回,我們實體類中定義的屬性,然后在apply()方法中才能接收到我們賦值的屬性參數(shù)!
注意:如果自定義的實體中有多個屬性需要判斷,
shortcutFieldOrder()方法中的順序要跟配置文件中的參數(shù)順序一致
那么當(dāng)我們編寫了該斷言工廠后,如果讓之生效?@Component 這個注解肯定必不可少了,目的就是讓 Spring 容器管理。那么已經(jīng)注冊的斷言工廠如何聲明使用呢?那就得回到配置文件了!

我們這里重點看 predicates 這個配置項下的配置,分別有三個配置,一個是我們已經(jīng)熟悉的 Path ,其他兩個有點陌生,但是這里再看看 Custom 是不是又有點眼熟?是的,我們在上面好像定義了一個叫 CustomRoutePredicate 的斷言工廠,兩者有點相似,又好像差點什么。那我就再給你一個提示:

我們看下抽象的斷言工廠有哪些自實現(xiàn)的類!其中是不是有 PathRoutePredicateFactory,沒錯,就是你想的那樣!有沒有一種撥開雨霧見青天的感覺!原來我們配置文件的 key 是以類名的前綴聲明的,也就是說斷言工廠類的格式必須是:自定義名稱+ RoutePredicateFactory 為后綴,然后在配置文件中聲明。這樣子舉一反三,我們自然而然的就清楚了 - Before 的作用,該作用便是:限制請求時間在 xxx 之前。
而 - Custom=cbuc,這個 cbuc 便是我們限制的規(guī)則,只有 name 為 cbuc 的用戶才能請求成功。如果有多個參數(shù),可以用, 隔開,順序需要與斷言工廠中shortcutFieldOrder() 返回參數(shù)的順序一致!
如果在自定義斷言工廠的途中遇到了什么阻礙,不然看看內(nèi)置的斷言工廠是如何實現(xiàn)的。
多看源碼總沒錯!
2. 過濾器
接下來進入第二個核心,也就是過濾器。該核心的作用也挺簡單,就是在請求的傳遞過程中,對請求和響應(yīng)做一系列的手腳。為了怕你劃回去看請求流程過于麻煩,小菜貼心的再貼一遍流程圖:

在 Gateway 的過濾器中又可以分為 局部過濾器 和 全局過濾器。聽名稱就知道其作用,局部 是用于某一個路由上的,全局 是用于所有路由上的。不過不管是 局部 還是 全局,生命周期都分為 pre 和 post。
- pre: 作用于路由到微服務(wù)之前調(diào)用。我們可以利用這種過濾器實現(xiàn)身份驗證、在集群中選擇請求的微服務(wù),記錄調(diào)試記錄等
- post: 作用于路由到微服務(wù)之后執(zhí)行。我們可以利用這種過濾器用來響應(yīng)添加標準的 HTTP Header,收集統(tǒng)計信息和指標、將響應(yīng)從微服務(wù)發(fā)送到客戶端。
1)局部過濾器
局部過濾器是針對于單個路由的過濾器。同樣 Gateway 已經(jīng)內(nèi)置了許多過濾器

我們選幾種常用的過濾器進行說明:(下列過濾器省略后綴 GaewayFilterFactory,完整名稱為 前綴+后綴)
| 過濾器前綴 | 作用 | 參數(shù) |
|---|---|---|
| StripPrefix | 用于截斷原始請求的路徑 | 使用數(shù)字表示要截斷的路徑數(shù)量 |
| AddRequestHeader | 為原始請求添加 Header | Header 的名稱及值 |
| AddRequestParameter | 為原始請求添加請求參數(shù) | 參數(shù)名稱及值 |
| Retry | 針對不同的響應(yīng)進行重試 | reties、statuses、methods、series |
| RequestSize | 設(shè)置允許接收最大請求包的大小 | 請求包大小,單位字節(jié),默認5M |
| SetPath | 修改原始請求的路徑 | 修改后的路徑 |
| RewritePath | 重寫原始的請求路徑 | 原始路徑正則表達式以及重寫后路徑的正則表達式 |
| PrefixPath | 為原始請求路徑添加前綴 | 前綴路徑 |
| RequestRateLimiter | 對請求限流,限流算法為令牌桶 | KeyResolver、reteLimiter、statusCode、denyEmptyKey |
內(nèi)置的過濾器小伙伴們可以自己嘗試一番,有問題歡迎提問!
我們接下來講講如何自定義過濾器工廠。don't say so much,我們上代碼
CustomGatewayFilterFactory

配置文件

當(dāng)我們開啟請求計數(shù)的時候,可以看到控制臺對于請求次數(shù)作了統(tǒng)計:

因此我們可以通過這種方式輕松實現(xiàn)局部過濾器
2)全局過濾器
全局過濾器作用于所有路由,無需配置。通過全局過濾器可以實現(xiàn)對權(quán)限的統(tǒng)一校驗,安全性驗證等功能
老樣子,我們先看看 Gateway 中存在哪些全局過濾器:

相對于局部過濾器,全局過濾器的命名就沒有太多約束了,畢竟不需要在配置文件中進行配置。
我們熟悉一下經(jīng)典的全局過濾器
| 過濾器名稱 | 作用 |
|---|---|
| ForwardPathFilter / ForwardRoutingFilter | 路徑轉(zhuǎn)發(fā)相關(guān)過濾器 |
| LoadBalanceerClientFilter | 負載均衡客戶端相關(guān)過濾器 |
| NettyRoutingFilter / NettyWriteResponseFilter | Http 客戶端相關(guān)過濾器 |
| RouteToRequestUrlFilter | 路由 URL 相關(guān)過濾器 |
| WebClientHttpRoutingFilter ?/ WebClientWriteResponseFilter | 請求 WebClient 客戶端轉(zhuǎn)發(fā)請求真實的URL并將響應(yīng)寫入到當(dāng)前的請求響應(yīng)中 |
| WebsocketRoutingFilter | websocket 相關(guān)過濾器 |
了解完內(nèi)置的過濾器,我們再看看如何定義全局的過濾器!
CustomerGlobalFilter

對于全局過濾器,我們不需要在配置文件中配置,因為是作用于所有路由
測試結(jié)果
success

fail

可以看到,我們使用全局過濾器進行了鑒權(quán)處理,如果沒有攜帶 token 將無法訪問!

到這里我們已經(jīng)了解到了服務(wù)網(wǎng)關(guān)的路由轉(zhuǎn)發(fā),權(quán)限校驗甚至于可以基于斷言和過濾器做出粗略簡單的 API監(jiān)控和限流
但其實對于 API監(jiān)控和 限流,SpringCloud 中已經(jīng)有了更好的組件完成這兩項工作。畢竟單一原則,做的越多往往錯的也越多!
后面會繼續(xù)整理關(guān)于 SpringCloud 組件的文章,敬請關(guān)注!
對于微服務(wù)的框架,孰好孰壞由我們自己判定。但是不管孰好孰壞,面對一門新技術(shù)的產(chǎn)生,我們最需要做的便是接收它,包容它,然后用好它,是騾子是馬,自己溜溜就知道了。
不要空談,不要貪懶,和小菜一起做個吹著牛X做架構(gòu)的程序猿吧~點個關(guān)注做個伴,讓小菜不再孤單。咱們下文見!
看完不贊,都是壞蛋今天的你多努力一點,明天的你就能少說一句求人的話!
我是小菜,一個和你一起變強的男人。
??微信公眾號已開啟,小菜良記,沒關(guān)注的同學(xué)們記得關(guān)注哦!
