天天看點

Spring Cloud Alibaba 系列之 Gateway(網關)

 一、前言

Spring Cloud 原先整合 Zuul 作為網關元件,Zuul 由 Netflix 公司提供的,現在已經不維護了。後面 Netflix 公司又出來了一個 Zuul2.0 網關,但由于一直沒有釋出穩定版本,是以 Spring Cloud 等不及了就自己推出一個網關,已經不打算整合 zuul2.0 了。

Spring Cloud Gateway 是 Spring 公司基于 Spring 5.0, Spring Boot 2.0 和 Project Reactor 等技術開發的網關,它旨在為微服務架構提供一種簡單有效的統一的 API 路由管理方式。它的目标是替代 Netflix Zuul,其不僅提供統一的路由方式,并且基于 Filter 鍊的方式提供了網關基本的功能,例如:安全,監控和限流。

二、Gateway 介紹

路由:網關的基本建構組成,表示一個具體的路由資訊載體。它由 ID,目标 URI,謂詞集合和過濾器集合定義

謂詞/斷言:Java 8 函數謂詞,輸入類型是 Spring Framework ServerWebExchange,可以比對 HTTP 請求中的所有内容,例如請求頭或參數

過濾器:使用特定工廠構造的 Spring Framework GatewayFilter 執行個體,可以在發送給下遊請求之前或之後修改請求和響應

Spring Cloud Alibaba 系列之 Gateway(網關)
Spring Cloud Alibaba 系列之 Gateway(網關)

執行流程大體如下:

Gateway Client 向 Gateway Server 發送請求

請求首先會被 HttpWebHandlerAdapter 進行提取組裝成網關上下文

然後網關的上下文會傳遞到 DispatcherHandler,它負責将請求分發給 RoutePredicateHandlerMapping

RoutePredicateHandlerMapping 負責路由查找,并根據路由斷言判斷路由是否可用

如果過斷言成功,由 FilteringWebHandler 建立過濾器鍊并調用

請求會一次經過 PreFilter -> 微服務 -> PostFilter 的方法,最終傳回響應

三、環境搭建

為了更好的了解上邊提到核心概念,我們現用簡單的實戰案例示範。

項目名稱

端口

描述

gateway-test

-

pom 項目,父工廠

user-service

9001

使用者微服務,服務注冊到 nacos

gateway-service

9090

網關服務,服務注冊到 nacos

注意:搭建項目啟動前,必須先開啟 Nacos 服務。 

該工程為 pom 項目,隻需要添加如下依賴:

Spring Cloud Alibaba 系列之 Gateway(網關)

該項目為使用者微服務,模拟提供使用者相關接口。

1. 添加依賴:

Spring Cloud Alibaba 系列之 Gateway(網關)

2. 配置檔案(application.yml):

Spring Cloud Alibaba 系列之 Gateway(網關)

3.業務類:

Spring Cloud Alibaba 系列之 Gateway(網關)
Spring Cloud Alibaba 系列之 Gateway(網關)

4.啟動類:

Spring Cloud Alibaba 系列之 Gateway(網關)

啟動使用者微服務,浏覽器輸入:h t t p:// localhost:9001/user/findById/1,結果如下圖:

Spring Cloud Alibaba 系列之 Gateway(網關)
Spring Cloud Alibaba 系列之 Gateway(網關)

使用者微服務正常。

該服務提供網關功能,核心就是配置路由規則。

1.添加依賴:

Spring Cloud Alibaba 系列之 Gateway(網關)

2.配置檔案(application.yml):

Spring Cloud Alibaba 系列之 Gateway(網關)

我們暫不配置路由規則。

3.啟動類:

Spring Cloud Alibaba 系列之 Gateway(網關)

啟動網關項目,我們試着通過網關請求使用者微服務接口。

請求規則:網關位址/微服務應用名/接口

我們在浏覽器輸入:h t t p://localhost:9090/user-service/user/findById/2,結果如下圖:

Spring Cloud Alibaba 系列之 Gateway(網關)
Spring Cloud Alibaba 系列之 Gateway(網關)

請求成功,網關項目搭建完成。

使用路由規則:

Spring Cloud Alibaba 系列之 Gateway(網關)

其中:

id: 路由辨別符,差別于其他 Route

uri:路由指向的目的地 uri,即用戶端請求最終被轉發到的微服務

predicate:斷言,用于條件判斷,隻有斷言都傳回真,才會真正的執行路由

filter:過濾器用于修改請求和響應資訊

添加 routes 相關配置,重新開機網關項目,請求使用者微服務接口。

請求規則:網關位址/斷言配置的 Path 路徑/接口

我們在浏覽器輸入:h t t p://localhost:9090/user-api/user/findById/3,結果如下圖:

Spring Cloud Alibaba 系列之 Gateway(網關)
Spring Cloud Alibaba 系列之 Gateway(網關)

路由規則生效。

簡單的使用了路由規則,下文将具體介紹路由規則的使用方式。

四、斷言

Predicate(斷言, 謂詞) 用于進行條件判斷,隻有斷言都傳回真,才會真正的執行路由。

SpringCloud Gateway 的斷言通過繼承 AbstractRoutePredicateFactory 類實作,是以我們可以根據自己的需求自定義斷言。

當然,開發團隊已為使用者提供了一些内置斷言工廠,在開發中已足夠使用,請繼續閱讀下文。

Spring Cloud Gateway 包括 11 種内置的斷言工廠,所有這些斷言都與 HTTP 請求的不同屬性比對。

補充:斷言可以同時使用

AfterRoutePredicateFactory:接收一個日期參數,判斷請求日期是否晚于指定日期

BeforeRoutePredicateFactory:接收一個日期參數,判斷請求日期是否早于指定日期

BetweenRoutePredicateFactory:接收兩個日期參數,判斷請求日期是否在指定時間段内

上邊三個斷言工廠都是根據時間判斷。使用方式如下:

Spring Cloud Alibaba 系列之 Gateway(網關)

我們設定在 2021年10月01日之後才能通路接口,目前請求時間為 2021年08月12日,請求結果如下圖:

Spring Cloud Alibaba 系列之 Gateway(網關)
Spring Cloud Alibaba 系列之 Gateway(網關)

請求接口失敗。

4.CookieRoutePredicateFactory: 接收兩個參數,cookie 名字和值。 判斷請求 cookie 是否具有給定名稱且值與正規表達式比對。

Spring Cloud Alibaba 系列之 Gateway(網關)

其中,token 為 cookie 名稱,123456 為 cookie 值。

我們可以支援 curl 的工具測試,鍵入 <code>curl http://localhost:9090/user-api/user/findById/3 --cookie token=123456</code>,結果如下圖:

Spring Cloud Alibaba 系列之 Gateway(網關)
Spring Cloud Alibaba 系列之 Gateway(網關)

5.HeaderRoutePredicateFactory:接收兩個參數,标題名稱和正規表達式。 判斷請求 Header 是否具有給定名稱且值與正規表達式比對。

Spring Cloud Alibaba 系列之 Gateway(網關)

其中,X-Request-Id 為 header 名稱,\d+ 為正規表達式,表示數字。

我們可以支援 curl 的工具測試,鍵入 <code>curl http://localhost:9090/user-api/user/findById/3 --header "X-Request-Id:9527"</code>,結果如下圖:

Spring Cloud Alibaba 系列之 Gateway(網關)
Spring Cloud Alibaba 系列之 Gateway(網關)

6.HostRoutePredicateFactory:接收一個參數,主機名模式。判斷請求的 Host 是否滿足比對規則。

Spring Cloud Alibaba 系列之 Gateway(網關)

支援 URI 模闆變量(例如{sub} .myhost.org),如果請求的主機标頭的值為w w w.somehost.org或 beta.somehost.org 或 w w w.anotherhost.org,則此路由比對

4.MethodRoutePredicateFactory: 接收一個參數,判斷請求類型是否跟指定的類型比對。

Spring Cloud Alibaba 系列之 Gateway(網關)

如果請求方法是 GET 或 POST,則此路由比對。

7.PathRoutePredicateFactory:接收一個參數,判斷請求的 URI 部分是否滿足路徑規則。

Spring Cloud Alibaba 系列之 Gateway(網關)

這個就是我們在上邊配置的斷言,請求是 <code>/user-api/</code> 開頭,則路由到使用者微服務上。

8.QueryRoutePredicateFactory:接收兩個參數,請求 param 和正規表達式, 判斷請求參數是否具有給定名稱且值與正規表達式比對。

Spring Cloud Alibaba 系列之 Gateway(網關)

請求包含名稱為 cardId 的參數,且參數值為數字,則比對路由。

測試如下:

Spring Cloud Alibaba 系列之 Gateway(網關)
Spring Cloud Alibaba 系列之 Gateway(網關)

9.RemoteAddrRoutePredicateFactory:接收一個 IP 位址段,判斷請求主機位址是否在位址段中

Spring Cloud Alibaba 系列之 Gateway(網關)

其中,192.168.0.1 是 IP 位址,而 16 是子網路遮罩。當請求的遠端位址為該值時,比對路由。

10.WeightRoutePredicateFactory:接收一個[組名,權重], 然後對于同一個組内的路由按照權重轉發。

Spring Cloud Alibaba 系列之 Gateway(網關)

配置多組路由規則時使用。路由會将約 80% 的流量轉發至 weighthigh.org,并将約 20% 的流量轉發至 weightlow.org。

當内置的斷言不滿足我們的業務需求時,我們可以自定義斷言工廠。

比如,我們需要判斷請求 url 中傳過來的 age 值在 18~60 範圍才可正常路由。

1. 配置斷言:

Spring Cloud Alibaba 系列之 Gateway(網關)

2. 我們需要建立一個類繼承 AbstractRoutePredicateFactory 類:

注意:自定義類名有格式要求-&gt; 斷言名稱 + RoutePredicateFactory。此處斷言名稱為 Age,對應配置檔案中的 Age。

Spring Cloud Alibaba 系列之 Gateway(網關)

3. 儲存,重新開機網關項目,測試結果如下:

Spring Cloud Alibaba 系列之 Gateway(網關)
Spring Cloud Alibaba 系列之 Gateway(網關)

五、過濾器

路由過濾器允許以某種方式修改傳入的 HTTP 請求或傳出的 HTTP 響應。

在 Gateway 中, Filter 的生命周期隻有兩個: “pre” 和 “post”。

PRE:這種過濾器在請求被路由之前調用。我們可利用這種過濾器實作身份驗證、在叢集中選擇請求的微服務、記錄調試資訊等

POST:這種過濾器在路由到微服務以後執行。這種過濾器可用來為響應添加标準的 HTTP Header、收集統計資訊和名額、将響應從微服務發送給用戶端等。

根據 Filter 的作用範圍可以分成兩種:GatewayFilter 與 GlobalFilter。

GatewayFilter:應用到單個路由或者一個分組的路由上。

GlobalFilter:應用到所有的路由上。

局部過濾器是針對單個路由的過濾器。

Spring Cloud Gateway 也提供了 31 種局部的内置 GatewayFilter 工廠。

由于數量較多,筆者隻列舉部分内置局部過濾器進行展示。

過濾器工廠

作用

參數

AddRequestHeader

為原始請求添加Header

Header的名稱及值

AddRequestParameter

為原始請求添加請求參數

參數名稱及值

AddResponseHeader

為原始響應添加Header

DedupeResponseHeader

剔除響應頭中重複的值

需要去重的Header名稱及去重政策

PrefixPath

為原始請求路徑添加字首

字首路徑

RequestRateLimiter

用于對請求限流, 限流算法為令牌桶

keyResolver、rateLimiter、statusCode、denyEmptyKey、emptyKeyStatus

RedirectTo

将原始請求重定向到指定的URL

http狀态碼及重定向的url

StripPrefix

用于截斷原始請求的路徑

使用數字表示要截斷的路徑的數量

Retry

針對不同的響應進行重試

retries、 statuses、methods、 series

ModifyRequestBody

在轉發請求之前修改原始請求體内容

修改後的請求體内容

ModifyResponseBody

修改原始響應體的内容

修改後的響應體内容

SetStatus

修改原始響應的狀态碼

HTTP 狀态碼, 可以是數字, 也可以是字元串

使用方式:

Spring Cloud Alibaba 系列之 Gateway(網關)

同樣地,當内置的局部過濾器不符合我們的業務需求時,我們也可以自定義過濾器。

比如:我們需要在調用/路由一個接口之前列印一下日志。

1. 配置局部過濾器

Spring Cloud Alibaba 系列之 Gateway(網關)

2. 建立一個類繼承 AbstractGatewayFilterFactory 類:

注意:自定義類名有格式要求-&gt; 過濾器名稱 + GatewayFilterFactory。此處過濾器名稱為 Log,對應配置檔案中的 Log。

Spring Cloud Alibaba 系列之 Gateway(網關)
Spring Cloud Alibaba 系列之 Gateway(網關)
Spring Cloud Alibaba 系列之 Gateway(網關)

全局過濾器作用于所有路由, 無需配置。通過全局過濾器可以實作對權限的統一校驗,安全性驗證等功能。

同樣地,架構也内置了一些全局過濾器,它們都實作 GlobalFilter 和 Ordered 接口。有興趣的讀者可以自行檢視 GlobalFilter 的實作類或浏覽下文提供的官方文檔擷取詳細資訊。

這裡我們主要示範自定義全局過濾器。

比如:我們在接受請求時需要驗證 token。

由于是全局過濾器,是以無需修改配置檔案,需要定義類實作 GlobalFilter 和 Ordered 接口。

Spring Cloud Alibaba 系列之 Gateway(網關)

儲存,重新開機網關項目,測試結果如下:

Spring Cloud Alibaba 系列之 Gateway(網關)
Spring Cloud Alibaba 系列之 Gateway(網關)

token 驗證失敗,傳回 401,鑒權失敗的提示;token 驗證成功,傳回接口結果。

六、 路由失敗處理

當請求路由位址不比對或斷言為 false 時,Gateway 會預設傳回 Whitelabel Error Page 錯誤頁面,這種錯誤提示不符合我們業務需求。

1. 我們可以自定義傳回一個較為友好的錯誤提示,需要建立一個類繼承 DefaultErrorWebExceptionHandler 類,重寫其方法:

Spring Cloud Alibaba 系列之 Gateway(網關)

2. 配置 Bean 執行個體:

Spring Cloud Alibaba 系列之 Gateway(網關)

3. 儲存後重新開機網關項目,請求一個錯誤的接口位址,結果如下:

Spring Cloud Alibaba 系列之 Gateway(網關)
Spring Cloud Alibaba 系列之 Gateway(網關)

請求的 url 位址不比對路由規則傳回我們定義的錯誤提示。

七、跨域問題

針對 PC 端的頁面請求,如果項目前後端分離,則請求會出現跨域請求問題。為什麼呢?接着看。

URL 由協定、域名、端口和路徑組成,如果兩個 URL 的協定、域名和端口相同,則表示它們同源,否則反之。

浏覽器提供同源政策,限制了來自不同源的 document 或腳本,對目前 document 讀取或設定某些屬性。其目的是為了保證使用者資訊的安全,防止惡意的網站竊取資料。

下面筆者示範跨域問題,編寫一個簡單頁面:

Spring Cloud Alibaba 系列之 Gateway(網關)

啟動一個服務容器(筆者采用 sublime 的插件),配置設定了 10800 端口,請求結果如下:

Spring Cloud Alibaba 系列之 Gateway(網關)
Spring Cloud Alibaba 系列之 Gateway(網關)

由于請求端的端口與網關端口不一緻,不是同源,是以出現跨域問題。

解決方案有兩種,如下:

方式一:修改配置檔案

Spring Cloud Alibaba 系列之 Gateway(網關)

方式二:配置 CorsWebFilter 過濾器

Spring Cloud Alibaba 系列之 Gateway(網關)

八、整合 Sentinel

網關作為微服務,我們也可以對其進行限流和降級操作。

注意:配置前記得啟動 Sentinel 控制台。

Spring Cloud Alibaba 系列之 Gateway(網關)

2. 修改配置檔案,連接配接 Sentinel 控制台:

Spring Cloud Alibaba 系列之 Gateway(網關)

3. 配置 Sentinel Filter 執行個體

Spring Cloud Alibaba 系列之 Gateway(網關)

最後,重新開機網關微服務,在 Sentinel 控制台檢視或配置規則即可。

在 Sentinel 控制台配置規後,服務出現限流或降級時,我們需要服務端傳回友好的異常資訊,而不是一個簡單的錯誤頁面。

我們需要配置 BlockRequestHandler 執行個體。

Spring Cloud Alibaba 系列之 Gateway(網關)
Spring Cloud Alibaba 系列之 Gateway(網關)

注意:當多個 Bean 上都配置 @Order 注解時,要多留意 order 值,否則接口請求後達不到預期效果

 最後

需要完整版的小夥伴,可以一鍵三連後,點選這裡!