全網首發Spring Cloud Gateway 添加統一前綴功能

  • 2019 年 12 月 8 日
  • 筆記

1. 前言

今天學習一下Spring Cloud Gateway,就先再其他博客上逛了逛。遇到有java開發者在某博客問一個問題:Spring Cloud Gateway 如何添加統一的前綴? 當時沒有在意,但是腦子裡也帶着這個問題看起了文檔。隨着慢慢了解Spring Cloud Gateway 這個問題就有了一點思路。

2.Gateway工作機制

這是官方文檔上給的Spring Cloud Gateway工作流程圖。大意上是客戶端請求經過HandlerMapping的處理,如果匹配到路由(Router)就交給網關的web處理程序(Gateway Web Handler)來處理,經過一系列的調用過濾器鏈(肯定有責任鏈模式)後轉發到被代理的服務執行真正的調用邏輯。

3. Gateway Handler Mapping

根據上圖,我想找到所謂的Gateway Handler Mapping,看看是何方神聖。我找到了RoutePredicateHandlerMapping,並確定該類就是那個handler Mapping。依賴於Spring Webflux響應式web編程模型。核心方法是getHandlerInternal,通過該方法進行內部處理。

從代碼上看 就是處理了端口關係後,在request放入一些gateway特定的attribute。然後走的一個尋找路由的方法。最後通過Mono.just(webHandler)交給了一個FilteringWebHandler類型的webHandler來處理了。我們先來關注lookupRoute方法,該方法擺明了就是尋找路由。該方法的代碼不貼了。就是通過routeLocator.getRoutes()來加載所有的路由並通過斷言(Predicate)來進行匹配。匹配到就交給FilteringWebHandler 走過濾器鏈。在我明白這個流程之後,腦子裡那個問題就有了眉目。

4. FilteringWebHandler

該handler就是圖中的Gateway Web Handler ,包含了一系列的GlobalFilter和GatewayFilter 來組成一個chain來處理前置和後置的邏輯,然後交給具體代理的服務。

5. 增加統一前綴的思路

在以前我們知道zuul網關是可以添加一個統一前綴的。但是Spring Cloud Gateway是沒有直接提供這個功能的。我已經搞清楚了Gateway的大致工作機制,甚至是一些細節。首先這個統一前綴肯定不能在斷言中處理。斷言是根據請求的個性化來找目的地路由的,而統一前綴是共性的。放在斷言執行後也就是FilteringWebHandler來處理就更不合適了。因為斷言執行在Filter之前。

有一個東西我們沒有注意到。Spring Cloud Gateway的機制依賴於Spring Webflux框架的。經過查一些資料RoutePredicateHandlerMapping處理之前是可以設置WebFilter的。因此我找到了一個解決方案:在Gateway Client 和 Gateway Handler Mapping 之間定製一個WebFilter來處理統一前綴。

6. 思路實現

機制是這樣的,請求帶統一前綴請求經過我定製的WebFilter去掉前綴(當然你可以加一些其他你需要的邏輯)然後交給Gateway Handler Mapping處理。代碼如下:

經過測試有效。

7. 總結

這裡其實重點不是如何來實現這個功能,我想傳達的是一個解決問題的思路。如何從框架的工作機制出發來分析你所需要解決的問題。找到那個合適的切入點。思路清晰了對於解決問題來說至關重要。其實我現在對Spring Cloud Gateway和Spring Webflux 都並不是很熟練,但是依然找了一個解決問題的方法。不知道你有沒有更好的方法呢?相關代碼已經上傳到碼雲倉庫:

https://gitee.com/felord/tino-cloud.git