Spring Cloud Gateway 之 Predict

文章首發(fā)于公眾號(hào)公眾號(hào)《程序員果果》
地址:https://mp.weixin.qq.com/s/2twx-aCEM2GXluDUIubGZg

Spring Cloud gateway工作流程

在之前的文章的Spring Cloud Gateway初體驗(yàn)中,大家已經(jīng)對(duì)Spring Cloud Gateway的功能有一個(gè)初步的認(rèn)識(shí),網(wǎng)關(guān)作為一個(gè)系統(tǒng)的流量的入口,有著舉足輕重的作用,通常的作用如下:

  • 協(xié)議轉(zhuǎn)換,路由轉(zhuǎn)發(fā)
  • 流量聚合,對(duì)流量進(jìn)行監(jiān)控,日志輸出
  • 作為整個(gè)系統(tǒng)的前端工程,對(duì)流量進(jìn)行控制,有限流的作用
  • 作為系統(tǒng)的前端邊界,外部流量只能通過網(wǎng)關(guān)才能訪問系統(tǒng)
  • 可以在網(wǎng)關(guān)層做權(quán)限的判斷
  • 可以在網(wǎng)關(guān)層做緩存

Spring Cloud Gateway作為Spring Cloud框架的第二代網(wǎng)關(guān),在功能上要比Zuul更加的強(qiáng)大,性能也更好。隨著Spring Cloud的版本迭代,Spring Cloud官方有打算棄用Zuul的意思。在筆者調(diào)用了Spring Cloud Gateway的使用和功能上,Spring Cloud Gateway替換掉Zuul的成本上是非常低的,幾乎可以無縫切換。Spring Cloud Gateway幾乎包含了zuul的所有功能。


如上圖所示,客戶端向Spring Cloud Gateway發(fā)出請(qǐng)求。 如果Gateway Handler Mapping確定請(qǐng)求與路由匹配(這個(gè)時(shí)候就用到predicate),則將其發(fā)送到Gateway web handler處理。 Gateway web handler處理請(qǐng)求時(shí)會(huì)經(jīng)過一系列的過濾器鏈。 過濾器鏈被虛線劃分的原因是過濾器鏈可以在發(fā)送代理請(qǐng)求之前或之后執(zhí)行過濾邏輯。 先執(zhí)行所有“pre”過濾器邏輯,然后進(jìn)行代理請(qǐng)求。 在發(fā)出代理請(qǐng)求之后,收到代理服務(wù)的響應(yīng)之后執(zhí)行“post”過濾器邏輯。這跟zuul的處理過程很類似。在執(zhí)行所有“pre”過濾器邏輯時(shí),往往進(jìn)行了鑒權(quán)、限流、日志輸出等功能,以及請(qǐng)求頭的更改、協(xié)議的轉(zhuǎn)換;轉(zhuǎn)發(fā)之后收到響應(yīng)之后,會(huì)執(zhí)行所有“post”過濾器的邏輯,在這里可以響應(yīng)數(shù)據(jù)進(jìn)行了修改,比如響應(yīng)頭、協(xié)議的轉(zhuǎn)換等。

在上面的處理過程中,有一個(gè)重要的點(diǎn)就是講請(qǐng)求和路由進(jìn)行匹配,這時(shí)候就需要用到predicate,它是決定了一個(gè)請(qǐng)求走哪一個(gè)路由。

Predicate 介紹

Predicate 來源于 Java 8,是 Java 8 中引入的一個(gè)函數(shù),Predicate 接受一個(gè)輸入?yún)?shù),返回一個(gè)布爾值結(jié)果。該接口包含多種默認(rèn)方法來將 Predicate 組合成其他復(fù)雜的邏輯(比如:與,或,非)??梢杂糜诮涌谡?qǐng)求參數(shù)校驗(yàn)、判斷新老數(shù)據(jù)是否有變化需要進(jìn)行更新操作。

在 Spring Cloud Gateway 中 Spring 利用 Predicate 的特性實(shí)現(xiàn)了各種路由匹配規(guī)則,有通過 Header、請(qǐng)求參數(shù)等不同的條件來進(jìn)行作為條件匹配到對(duì)應(yīng)的路由。網(wǎng)上有一張圖總結(jié)了 Spring Cloud 內(nèi)置的幾種 Predicate 的實(shí)現(xiàn)。

說白了 Predicate 就是為了實(shí)現(xiàn)一組匹配規(guī)則,方便讓請(qǐng)求過來找到對(duì)應(yīng)的 Route 進(jìn)行處理,接下來我們接下 Spring Cloud GateWay 內(nèi)置幾種 Predicate 的使用。

Predicate 實(shí)戰(zhàn)

通過時(shí)間匹配

Predicate 支持設(shè)置一個(gè)時(shí)間,在請(qǐng)求進(jìn)行轉(zhuǎn)發(fā)的時(shí)候,可以通過判斷在這個(gè)時(shí)間之前或者之后進(jìn)行轉(zhuǎn)發(fā)。比如我們現(xiàn)在設(shè)置只有在2019年2月15日才會(huì)轉(zhuǎn)發(fā)到我的簡(jiǎn)書地址,在這之前不進(jìn)行轉(zhuǎn)發(fā),我就可以這樣配置:

spring:
  cloud:
    gateway:
      routes:
        - id: after_route
          uri: http://httpbin.org
          predicates:
          - After=2018-02-15T00:00:00+08:00[Asia/Shanghai]

Spring 是通過 ZonedDateTime 來對(duì)時(shí)間進(jìn)行的對(duì)比,ZonedDateTime 是 Java 8 中日期時(shí)間功能里,用于表示帶時(shí)區(qū)的日期與時(shí)間信息的類,ZonedDateTime 支持通過時(shí)區(qū)來設(shè)置時(shí)間,中國的時(shí)區(qū)是:Asia/Shanghai。

After Route Predicate 是指在這個(gè)時(shí)間之后的請(qǐng)求都轉(zhuǎn)發(fā)到目標(biāo)地址。上面的示例是指,請(qǐng)求時(shí)間在 2019年2月15日0點(diǎn)0分0秒之后的所有請(qǐng)求都轉(zhuǎn)發(fā)到地址http://httpbin.org。+08:00是指時(shí)間和UTC時(shí)間相差八個(gè)小時(shí),時(shí)間地區(qū)為Asia/Shanghai

添加完路由規(guī)則之后,訪問地址 http://127.0.0.1:8080/get 會(huì)自動(dòng)轉(zhuǎn)發(fā)到 http://httpbin.org/get

Before Route Predicate 剛好相反,在某個(gè)時(shí)間之前的請(qǐng)求的請(qǐng)求都進(jìn)行轉(zhuǎn)發(fā)。我們把上面路由規(guī)則中的 After 改為 Before,如下:

spring:
  cloud:
    gateway:
      routes:
        - id: before_route
          uri: http://httpbin.org
          predicates:
          - Before=2019-02-15T00:00:00+08:00[Asia/Shanghai]

就表示在2019-02-14之前可以進(jìn)行路由,在這時(shí)間之后停止路由,修改完之后重啟項(xiàng)目再次訪問地址http://localhost:8080,頁面會(huì)報(bào) 404 沒有找到地址。

除過在時(shí)間之前或者之后外,Gateway 還支持限制路由請(qǐng)求在某一個(gè)時(shí)間段范圍內(nèi),可以使用 Between Route Predicate 來實(shí)現(xiàn)。

spring:
  cloud:
    gateway:
      routes:
        - id: between_route
          uri: http://httpbin.org
          predicates:
          - Between=2018-02-14T00:00:00+08:00[Asia/Shanghai], 2019-02-16T23:59:59+08:00[Asia/Shanghai]

這樣設(shè)置就意味著在 2019-02-14到2019-02-16 時(shí)間段內(nèi)可以匹配到此路由,超過這個(gè)時(shí)間段范圍則不會(huì)進(jìn)行匹配。通過時(shí)間匹配路由的功能很酷,可以用在限時(shí)搶購的一些場(chǎng)景中。

通過 Cookie 匹配

Cookie Route Predicate 可以接收兩個(gè)參數(shù),一個(gè)是 Cookie name ,一個(gè)是正則表達(dá)式,路由規(guī)則會(huì)通過獲取對(duì)應(yīng)的 Cookie name 值和正則表達(dá)式去匹配,如果匹配上就會(huì)執(zhí)行路由,如果沒有匹配上則不執(zhí)行。

spring:
  cloud:
    gateway:
      routes:
        - id: cookie_route
          uri: http://httpbin.org:80
          predicates:
          - Cookie=name, chengxuyuanguoguo

上面的配置中,請(qǐng)求帶有cookie名為name, cookie值為chengxuyuanguoguo 的請(qǐng)求將都會(huì)轉(zhuǎn)發(fā)到uri為 http://httpbin.org的地址上。

使用 curl 測(cè)試,命令行輸入:

curl http://127.0.0.1:8080/get --cookie "name=chengxuyuanguoguo"

則有正確返回,如果去掉--cookie "name=chengxuyuanguoguo",沒有匹配成功,出現(xiàn) 404 錯(cuò)誤。

通過 Header 屬性匹配

Header Route Predicate 和 Cookie Route Predicate 一樣,也是接收 2 個(gè)參數(shù),一個(gè) header 中屬性名稱和一個(gè)正則表達(dá)式,這個(gè)屬性值和正則表達(dá)式匹配則執(zhí)行。

spring:
  cloud:
    gateway:
      routes:
        - id: header_route
          uri: http://httpbin.org
          predicates:
          - Header=X-Request-Id, \d+

使用 curl 測(cè)試,命令行輸入:

curl http://127.0.0.1:8080/get  -H "X-Request-Id:111111" 

則正常返回,將參數(shù) "X-Request-Id:111111" 改為 "X-Request-Id:xxxx" 再次執(zhí)行時(shí)返回404。

通過 Host 匹配

Host Route Predicate 接收一組參數(shù),一組匹配的域名列表,這個(gè)模板是一個(gè) ant 分隔的模板,用.號(hào)作為分隔符。它通過參數(shù)中的主機(jī)地址作為匹配規(guī)則。

spring:
  cloud:
    gateway:
      routes:
      - id: host_route
        uri: http://ityouknow.com
        predicates:
        - Host=**.ityouknow.com

使用 curl 測(cè)試,命令行輸入:

curl http://127.0.0.1:8080/get  -H "Host:www.httpbin.com" 

測(cè)試上述 host 可匹配到 host_route 路由,去掉 host 參數(shù)則會(huì)報(bào) 404 錯(cuò)誤。

通過請(qǐng)求方式匹配

可以通過是 POST、GET、PUT、DELETE 等不同的請(qǐng)求方式來進(jìn)行路由。

spring:
  cloud:
    gateway:
      routes:
        - id: method_route
          uri: http://httpbin.org
          predicates:
          - Method=GET

使用 curl 測(cè)試,命令行輸入:

curl http://127.0.0.1:8080/get

測(cè)試返回正確,證明匹配到路由,再以 POST 的方式請(qǐng)求測(cè)試:

curl -X POST http://127.0.0.1:8080/get

返回 404 沒有找到,沒有匹配上路由。

通過請(qǐng)求路徑匹配

Path Route Predicate 接收一個(gè)匹配路徑的參數(shù)來判斷是否走路由。

spring:
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: http://httpbin.org
          predicates:
            - Path=/foo/{segment}

使用 curl 測(cè)試,命令行輸入:

curl http://127.0.0.1:8080/foo/1
curl http://127.0.0.1:8080/fee/1

測(cè)試第一命令可以正常獲取到頁面返回值,第二個(gè)命令報(bào)404,證明路由是通過指定路由來匹配。

通過請(qǐng)求參數(shù)匹配

Query Route Predicate 支持傳入兩個(gè)參數(shù),一個(gè)是屬性名一個(gè)為屬性值,屬性值可以是正則表達(dá)式。

spring:
  cloud:
    gateway:
      routes:
        - id: query_route
          uri: http://httpbin.org
          predicates:
          - Query=foo

測(cè)試發(fā)現(xiàn)只要請(qǐng)求帶有 foo 參數(shù)即會(huì)匹配路由,不帶 foo 參數(shù)則會(huì)報(bào) 404 錯(cuò)誤。

通過請(qǐng)求 ip 地址進(jìn)行匹配

Predicate 也支持通過設(shè)置某個(gè) ip 區(qū)間號(hào)段的請(qǐng)求才會(huì)路由,RemoteAddr Route Predicate 接受 cidr 符號(hào)(IPv4 或 IPv6 )字符串的列表(最小大小 1),例如 192.168.0.1/16 (其中 192.168.0.1 是 IP 地址,16 是子網(wǎng)掩碼)。

spring:
  cloud:
    gateway:
      routes:
        - id: remoteaddr_route
          uri: http://httpbin.org
          predicates:
          - RemoteAddr=172.16.1.73/24

使用 curl 測(cè)試,命令行輸入:

curl http://172.17.1.73:8080/get

測(cè)試返回正確,改為請(qǐng)求 127.0.0.1:8080/get 則會(huì)報(bào) 404 錯(cuò)誤。

組合使用

Predicate還可以組合在一起使用。

spring:
  cloud:
    gateway:
      routes:
        - id: group_route
          uri: http://httpbin.org
          predicates:
          - Host=**.httpbin.com
          - Header=X-Request-Id, \d+
          - Cookie=name, chengxuyuanguoguo
          - After=2019-02-15T00:00:00+08:00[Asia/Shanghai]

使用 curl 測(cè)試,命令行輸入:

curl http://127.0.0.1:8080 -H "X-Request-Id:111111" -H "Host:www.httpbin.com" --cookie "name=chengxuyuanguoguo"

測(cè)試返回正確,錯(cuò)誤的規(guī)則或去除一個(gè)規(guī)則,則會(huì)報(bào) 404 錯(cuò)誤。

總結(jié)

Predict作為斷言,它決定了請(qǐng)求會(huì)被路由到哪個(gè)router 中。在斷言之后,請(qǐng)求會(huì)被進(jìn)入到filter過濾器的邏輯,下篇文章將會(huì)介紹Spring Cloud Gateway過濾器相關(guān)的內(nèi)容。

源碼下載:https://github.com/gf-huanchupk/SpringCloudLearning/tree/master/chapter13/springcloud-gateway-predict

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 目錄 1.How to Include Spring Cloud Gateway2.Glossary3.How I...
    彳亍者_(dá)ab41閱讀 1,914評(píng)論 0 3
  • 轉(zhuǎn)載請(qǐng)標(biāo)明出處:https://www.fangzhipeng.com本文出自方志朋的博客 在上一篇文章詳細(xì)的介紹...
    方志朋閱讀 2,756評(píng)論 0 14
  • 推薦指數(shù): 6.0 書籍主旨關(guān)鍵詞:特權(quán)、焦點(diǎn)、注意力、語言聯(lián)想、情景聯(lián)想 觀點(diǎn): 1.統(tǒng)計(jì)學(xué)現(xiàn)在叫數(shù)據(jù)分析,社會(huì)...
    Jenaral閱讀 6,031評(píng)論 0 5
  • 昨天,在回家的路上,坐在車?yán)镉圃沼圃盏乜粗摹度龉衬墓适隆?,我被里面的?nèi)容深深吸引住了,盡管上學(xué)時(shí)...
    夜闌曉語閱讀 3,958評(píng)論 2 9
  • 一。匹配。 判斷一個(gè)字符串是否符合我們制定的規(guī)則? 二…捕獲 字符串中符合我們正則表達(dá)式,規(guī)則的,內(nèi)容捕獲到。 三...
    時(shí)修七年閱讀 1,069評(píng)論 2 0

友情鏈接更多精彩內(nèi)容