<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          網(wǎng)關(guān)很重要,學(xué)一學(xué)Gateway

          共 8243字,需瀏覽 17分鐘

           ·

          2021-11-01 18:32

          介紹服務(wù)網(wǎng)關(guān)

          要認(rèn)識一樣?xùn)|西,最好的方法是從為什么需要他開始說起。

          按照現(xiàn)在主流使用微服務(wù)架構(gòu)的特點(diǎn),假設(shè)現(xiàn)在有A、B、C三個服務(wù),假如這三個服務(wù)都需要做一些請求過濾和權(quán)限校驗(yàn),請問怎么實(shí)現(xiàn)?

          • 每個服務(wù)自己實(shí)現(xiàn)一遍。
          • 寫在一個公共的服務(wù),然后讓A、B、C服務(wù)引入公共服務(wù)的Maven依賴。
          • 使用服務(wù)網(wǎng)關(guān),所有客戶端請求服務(wù)網(wǎng)關(guān)進(jìn)行請求過濾和權(quán)限校驗(yàn),然后再路由轉(zhuǎn)發(fā)到A、B、C服務(wù)。

          第一種方式顯然是逆天的,這里不做討論。第二種方法稍微聰明點(diǎn),但是如果公共服務(wù)的邏輯發(fā)生改變,那么所有依賴公共服務(wù)的服務(wù)都需要重新打包部署才能生效。

          所以顯而易見,使用服務(wù)網(wǎng)關(guān)則解決了以上的問題,其他服務(wù)不需要加入什么依賴,只需要在網(wǎng)關(guān)配置一些參數(shù),然后就能路由轉(zhuǎn)發(fā)到對應(yīng)的后端服務(wù),如果需要請求過濾和權(quán)限檢驗(yàn)的話,都可以在網(wǎng)關(guān)層實(shí)現(xiàn),如果需要更新權(quán)限校驗(yàn)的邏輯,只需要網(wǎng)關(guān)層修改就可以,其他后端服務(wù)不需要修改。

          接下來再介紹一下服務(wù)網(wǎng)關(guān)的功能,主要有:

          • 路由轉(zhuǎn)發(fā)
          • API監(jiān)控
          • 權(quán)限控制
          • 限流

          所以服務(wù)網(wǎng)關(guān)很重要!那么接下來我們就以目前比較主流的GateWay進(jìn)行學(xué)習(xí)吧。

          GateWay入門

          首先第一步需要創(chuàng)建一個作為網(wǎng)關(guān)的項(xiàng)目,這里使用的SpringBoot版本是2.0.1,引入依賴:

          <dependencies>
          ????<dependency>
          ????????<groupId>org.springframework.cloudgroupId>
          ????????<artifactId>spring-cloud-starter-gatewayartifactId>
          ????dependency>
          dependencies>

          <dependencyManagement>
          ????<dependencies>
          ????????<dependency>
          ????????????<groupId>org.springframework.cloudgroupId>
          ????????????<artifactId>spring-cloud-dependenciesartifactId>
          ????????????<version>Finchley.SR1version>
          ????????????<type>pomtype>
          ????????????<scope>importscope>
          ????????dependency>
          ????dependencies>
          dependencyManagement>

          我們需要使用網(wǎng)關(guān)轉(zhuǎn)發(fā)請求,那么首先需要有個后端服務(wù),這里我簡單地創(chuàng)建了一個user項(xiàng)目。然后啟動user項(xiàng)目,寫個獲取所有用戶信息的接口:

          babc5bb915a2c53c4973be54b93b5fef.webp

          那么我們現(xiàn)在配置網(wǎng)關(guān)的application.yml實(shí)現(xiàn)請求轉(zhuǎn)發(fā)。

          server:
          ??port:?9201
          spring:
          ??application:
          ????name:?api-gateway
          ??cloud:
          ????gateway:
          ??????routes:
          ????????-?id:?user_getList?#路由的ID
          ??????????uri:?http://localhost:8080/user/getList?#最終目標(biāo)的請求地址
          ??????????predicates:?#斷言
          ????????????-?Path=/user/getList?#路徑相匹配的進(jìn)行路由

          也就是說我請求http://localhost:9201/user/getList后,9201端口是網(wǎng)關(guān)服務(wù),會匹配/user/getList的路由,最終轉(zhuǎn)發(fā)到目標(biāo)地址http://localhost:8080/user/getList。

          bec4dddf7d76eef395deadceb5499c0c.webp

          這就算是gateway網(wǎng)關(guān)的簡單使用了。

          繼續(xù)深入

          在上面入門的例子中,我們注意到有個predicates的配置,有點(diǎn)對其似懂非懂的感覺。中文翻譯過來叫做斷言,有點(diǎn)類似于Java8的Stream流里的Predicate函數(shù)的意思。如果斷言是真的,則匹配路由。

          除此之外,gateway的另一個核心是Filter(過濾器),F(xiàn)ilter有全局和局部兩種。那么整個gateway的流程是怎么樣的呢?請看下圖:

          4c00cffa33e86537fcc8419f850a7827.webp

          從圖中可以看出,gateway的兩大核心就是斷言(Predicate)和過濾(Filter),接下來我們重點(diǎn)講講這兩者的使用。

          Route Predicate 的使用

          Spring Cloud Gateway包括許多內(nèi)置的Route Predicate工廠,所以可以直接通過配置直接使用各種內(nèi)置的Predicate。

          After Route Predicate

          在指定的時間之后請求匹配該路由。

          spring:
          ??cloud:
          ????gateway:
          ??????routes:
          ????????-?id:?user_getList
          ??????????uri:?http://localhost:8080/user/getList
          ??????????predicates:
          ????????????-?After=2021-10-30T01:00:00+08:00[Asia/Shanghai]

          Before Route Predicate

          在指定時間之前的請求會匹配該路由。

          spring:
          ??cloud:
          ????gateway:
          ??????routes:
          ????????-?id:?user_getList
          ??????????uri:?http://localhost:8080/user/getList
          ??????????predicates:
          ????????????-?Before=2021-10-30T02:00:00+08:00[Asia/Shanghai]

          Between Route Predicate

          在指定時間區(qū)間內(nèi)的請求會匹配該路由。

          spring:
          ??cloud:
          ????gateway:
          ??????routes:
          ????????-?id:?user_getList
          ??????????uri:?http://localhost:8080/user/getList
          ??????????predicates:
          ???????????-?Between=2021-10-30T01:00:00+08:00[Asia/Shanghai],2021-10-30T02:00:00+08:00[Asia/Shanghai]

          Cookie Route Predicate

          帶有指定Cookie的請求會匹配該路由。

          spring:
          ??cloud:
          ????gateway:
          ??????routes:
          ????????-?id:?user_getList
          ??????????uri:?http://localhost:8080/user/getList
          ??????????predicates:
          ???????????-?Cookie=username,yehongzhi

          使用POSTMAN發(fā)送帶有Cookie里username=yehongzhi的請求。

          35a0f4faea1887f9d266723380b2247f.webp

          Header Route Predicate

          帶有指定請求頭的請求會匹配該路由。

          spring:
          ??cloud:
          ????gateway:
          ??????routes:
          ????????-?id:?user_getList
          ??????????uri:?http://localhost:8080/user/getList
          ??????????predicates:
          ?????????-?Header=X-Id,?\d+

          使用POSTMAN發(fā)送請求頭帶有X-Id的請求。

          744db9611659c33fc35249abfe71b207.webp

          Host Route Predicate

          帶有指定Host的請求會匹配該路由。

          spring:
          ??cloud:
          ????gateway:
          ??????routes:
          ????????-?id:?user_getList
          ??????????uri:?http://localhost:8080/user/getList
          ??????????predicates:
          ????????????-?Host=**.yehongzhi.com

          使用POSTMAN發(fā)送請求頭帶有Host=www.yehongzhi.com的請求。

          e8a3fbf0ef17b248b15564faf29bdfa1.webp

          Path Route Predicate

          發(fā)送指定路徑的請求會匹配該路由。

          spring:
          ??cloud:
          ????gateway:
          ??????routes:
          ????????-?id:?user_getList
          ??????????uri:?http://localhost:8080/user/getList
          ??????????predicates:
          ????????????-?Path=/user/getList

          直接在瀏覽器輸入該地址http://localhost:9201/user/getList,即可訪問。

          Method Route Predicate

          發(fā)送指定方法的請求會匹配該路由。

          spring:
          ??cloud:
          ????gateway:
          ??????routes:
          ????????-?id:?user_getList
          ??????????uri:?http://localhost:8080/user/getList
          ??????????predicates:
          ????????????-?Method=POST

          用POSTMAN以POST方式發(fā)送請求。

          cab63145315b90eca03f0e8ea4d8ba14.webp

          Query Route Predicate

          帶指定查詢參數(shù)的請求可以匹配該路由。

          spring:
          ??cloud:
          ????gateway:
          ??????routes:
          ????????-?id:?user_query_byName
          ??????????uri:?http://localhost:8080/user/query/byName
          ??????????predicates:
          ????????????-?Query=name

          在瀏覽器輸入http://localhost:9201/user/query/byName?name=tom地址,發(fā)送請求。

          2187d29ed96965bcf7002f85c7ed8258.webp

          Weight Route Predicate

          使用權(quán)重來路由相應(yīng)請求,以下配置表示有80%的請求會被路由到localhost:8080,20%的請求會被路由到localhost:8081。

          spring:
          ??cloud:
          ????gateway:
          ??????routes:
          ????????-?id:?user_1
          ??????????uri:?http://localhost:8080
          ??????????predicates:
          ????????????-?Weight=group1,?8
          ????????-?id:?user_2
          ??????????uri:?http://localhost:8081
          ??????????predicates:
          ????????????-?Weight=group1,?2

          RemoteAddr Route Predicate

          從指定的遠(yuǎn)程地址發(fā)起的請求可以匹配該路由。

          spring:
          ??cloud:
          ????gateway:
          ??????routes:
          ????????-?id:?user_1
          ??????????uri:?http://localhost:8080/user/getList
          ??????????predicates:
          ????????????-?RemoteAddr=192.168.1.4

          使用瀏覽器請求。

          c459e4c10c0dd3e9ed2e5c6e16418e9e.webp

          組合使用

          spring:
          ??cloud:
          ????gateway:
          ??????routes:
          ????????-?id:?user_1
          ??????????uri:?http://localhost:8080/user/getList
          ??????????predicates:
          ????????????-?RemoteAddr=192.168.1.4
          ????????????-?Method=POST
          ????????????-?Cookie=username,yehongzhi
          ????????????-?Path=/user/getList

          使用POSTMAN發(fā)起請求,使用POST方式,uri是/user/getList,帶有Cookie,RemoteAddr。

          c459e4c10c0dd3e9ed2e5c6e16418e9e.webp自定義Predicate

          如果我們需要自定義Predicate,怎么玩呢?其實(shí)很簡單,看源碼,有樣學(xué)樣,需要繼承AbstractRoutePredicateFactory類。

          下面舉個例子,需求是token值為abc的則匹配路由,怎么寫呢,請看代碼:

          @Component
          public?class?TokenRoutePredicateFactory?extends?AbstractRoutePredicateFactory<TokenRoutePredicateFactory.Config>?{

          ????public?static?final?String?TOKEN_KEY?=?"tokenValue";

          ????public?TokenRoutePredicateFactory()?{
          ????????//當(dāng)前類的Config類,會利用反射創(chuàng)建Config并賦值,在apply傳回來
          ????????super(TokenRoutePredicateFactory.Config.class);
          ????}

          ????@Override
          ????public?List?shortcutFieldOrder()?{
          ????????//"tokenValue"跟Config的接收字段一致
          ????????return?Arrays.asList(TOKEN_KEY);
          ????}

          ????@Override
          ????public?Predicate?apply(Config?config)?{
          ????????//這里獲取的config對象就是下面自定義的Config對象
          ????????return?new?Predicate()?{
          ????????????@Override
          ????????????public?boolean?test(ServerWebExchange?exchange)?{
          ????????????????MultiValueMap?params?=?exchange.getRequest().getQueryParams();
          ????????????????//獲取請求參數(shù)
          ????????????????String?value?=?params.getFirst("token");
          ????????????????//請求參數(shù)和配置文件定義的token進(jìn)行對比,相等則返回true
          ????????????????return?config.getTokenValue()?!=?null?&&?config.getTokenValue().equals(value);
          ????????????}
          ????????};
          ????}
          ?//用來接收配置文件定義的值
          ????public?static?class?Config?{

          ????????private?String?tokenValue;

          ????????public?String?getTokenValue()?{
          ????????????return?tokenValue;
          ????????}

          ????????public?void?setTokenValue(String?tokenValue)?{
          ????????????this.tokenValue?=?tokenValue;
          ????????}
          ????}
          }

          這里需要注意的一點(diǎn)是類名必須是RoutePredicateFactory結(jié)尾,前面的則作為配置名。比如TokenRoutePredicateFactory的配置名則為Token,這是一個約定的配置。

          接著在配置文件中加上該配置:

          spring:
          ??cloud:
          ????gateway:
          ??????routes:
          ????????-?id:?user_1
          ??????????uri:?http://localhost:8080/user/getList
          ??????????predicates:
          ????????????-?Token=abc?##使用TokenRoutePredicateFactory進(jìn)行斷言

          然后用POSTMAN發(fā)送請求,帶上token參數(shù),參數(shù)值為abc。

          f151f4c507eb9fb99ea0118c834453fe.webp

          如果token的值不正確的話,會報404。

          5b9acd67f8056a6206afbfcfebb873e5.webp

          整合注冊中心

          為什么要整合注冊中心呢?因?yàn)槊總€服務(wù)一般背后都不只一臺機(jī)器,而且一般使用服務(wù)名進(jìn)行配置,而不是配置服務(wù)的IP地址,并且要實(shí)現(xiàn)負(fù)載均衡調(diào)用。

          這里我就使用Nacos作為注冊中心。

          引入Maven依賴:

          <dependency>
          ????<groupId>org.springframework.cloudgroupId>
          ????<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
          dependency>
          <dependencyManagement>
          ????<dependencies>
          ????????<dependency>
          ????????????<groupId>org.springframework.cloudgroupId>
          ????????????<artifactId>spring-cloud-dependenciesartifactId>
          ????????????<version>Finchley.SR1version>
          ????????????<type>pomtype>
          ????????????<scope>importscope>
          ????????dependency>
          ????????<dependency>
          ????????????<groupId>org.springframework.cloudgroupId>
          ????????????<artifactId>spring-cloud-alibaba-dependenciesartifactId>
          ????????????<version>0.2.2.RELEASEversion>
          ????????????<type>pomtype>
          ????????????<scope>importscope>
          ????????dependency>
          ????dependencies>
          dependencyManagement>

          啟動類加上注解,開啟注冊中心。

          @SpringBootApplication
          @EnableDiscoveryClient
          public?class?GatewayApplication?{
          ????public?static?void?main(String[]?args)?{
          ????????SpringApplication.run(GatewayApplication.class,?args);
          ????}
          }

          在application.yml加上配置:

          spring:
          ??application:
          ????name:?api-gateway
          ??cloud:
          ????nacos:
          ??????discovery:
          ????????server-addr:?127.0.0.1:8848
          ????????service:?${spring.application.name}
          ????gateway:
          ??????routes:
          ????????-?id:?consumer
          ??????????uri:?lb://consumer?#使用lb協(xié)議,consumer是服務(wù)名,不再使用IP地址配置
          ??????????order:?1
          ??????????predicates:
          ????????????-?Path=/consumer/**?#匹配/consumer/**的請求路徑
          server:
          ??port:?9201

          創(chuàng)建一個consumer也注冊到nacos,并提供一個接口:

          @RestController
          public?class?ConsumerController?{

          ????@Value("${server.port}")
          ????private?String?port;
          ????
          ????@RequestMapping("consumer/getDetail/{id}")
          ????public?String?getDetail(@PathVariable("id")?String?id)?{
          ????????return?"端口號:"?+?port?+?",獲取ID為:"?+?id?+?"的商品詳情";
          ????}
          }

          啟動consumer和gateway兩個項(xiàng)目,然后打開nacos控制臺,可以看到兩個服務(wù)。

          c93ba6fd11b5b51664b07e8f89547a5a.webp

          連續(xù)請求地址http://localhost:9201/consumer/getDetail/1,可以看到實(shí)現(xiàn)了負(fù)載均衡調(diào)用服務(wù)。

          055c8a6f0f24c328a3a4799683e3db33.webp8aac0af8a799ef5f93e2b827f7d3ef33.webp

          可能有人會覺得每個服務(wù)都要配一個路由,很麻煩。有個很簡單的配置可以解決這個問題:

          spring:
          ????gateway:
          ??????discovery:
          ????????locator:
          ??????????enabled:?true

          然后啟動服務(wù),再試一次,請求地址需要加上服務(wù)名,依然沒有問題!

          5f198d81501a56f661289b3b6223c3d1.webp寫在最后

          這篇文章主要介紹GateWay的路由轉(zhuǎn)發(fā)功能,并且整合了注冊中心。權(quán)限控制可以用過濾器實(shí)現(xiàn),由于篇幅有點(diǎn)長,過濾器放到下一篇文章了,感謝大家的閱讀。

          覺得有用就點(diǎn)個贊吧,你的點(diǎn)贊是我創(chuàng)作的最大動力~

          我是一個努力讓大家記住的程序員。我們下期再見?。?!

          能力有限,如果有什么錯誤或者不當(dāng)之處,請大家批評指正,一起學(xué)習(xí)交流!


          瀏覽 56
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  韩日黄色 | 日韩中文字幕有码 | 久久久免费黄色视频 | 亚洲欧美成人网站 | 人妻懂色av粉嫩av浪潮av |