亚洲精品中文免费|亚洲日韩中文字幕制服|久久精品亚洲免费|一本之道久久免费

      
      

            <dl id="hur0q"><div id="hur0q"></div></dl>

                SpringCloud系列-10Spring Cloud Gateway網(wǎng)關(guān)

                SpringCloud系列-10Spring Cloud Gateway網(wǎng)關(guān)

                學(xué)習(xí)目標(biāo)

              1. Gateway是什么?它有什么作用?
              2. Gateway中的斷言使用
              3. Gateway中的過濾器使用
              4. Gateway中的路由使用
              5. 第1章 網(wǎng)關(guān)

                1.1 網(wǎng)關(guān)的概念

                簡(jiǎn)單來說,網(wǎng)關(guān)就是一個(gè)網(wǎng)絡(luò)連接到另外一個(gè)網(wǎng)絡(luò)的“關(guān)口”。如下圖所示,當(dāng)我們所在的本地網(wǎng)絡(luò)(局域網(wǎng))要訪問外部網(wǎng)絡(luò)的數(shù)據(jù)時(shí),需要通過路由器進(jìn)行轉(zhuǎn)發(fā),而這里的路由器就充當(dāng)了網(wǎng)關(guān)的角色。

                1.2 網(wǎng)關(guān)的作用

                網(wǎng)關(guān)的作用,是可以實(shí)現(xiàn)不同網(wǎng)絡(luò)之間的互聯(lián),同時(shí),還可以使得在不同的通信協(xié)議、數(shù)據(jù)格式等系統(tǒng)之間實(shí)現(xiàn)轉(zhuǎn)發(fā)。

                我們今天要講解的Gateway,它也是網(wǎng)關(guān)的一種,我們稱為應(yīng)用網(wǎng)關(guān),也稱為API網(wǎng)關(guān)。為什么需要API網(wǎng)關(guān)呢? 還得從架構(gòu)演變過程來說明:

                前面我們說過,在微服務(wù)架構(gòu)中,每個(gè)微服務(wù)都是一個(gè)獨(dú)立運(yùn)行的組件,這些組件通過Rest API風(fēng)格的接口給到H5、Android、IOS等客戶端程序調(diào)用。(移動(dòng)互聯(lián)時(shí)代,為了盡快迭代)。而在一個(gè)UI界面中,通常會(huì)展示很多數(shù)據(jù),這些數(shù)據(jù)可能來自不同的微服務(wù),比如在一個(gè)電商系統(tǒng)中,執(zhí)行一個(gè)下單請(qǐng)求,必然需要

              6. 從營(yíng)銷服務(wù)中查詢促銷信息
              7. 從會(huì)員服務(wù)中查詢會(huì)員等級(jí)和會(huì)員積分等
              8. 從商品服務(wù)查詢商品詳情
              9. 調(diào)用訂單服務(wù)進(jìn)行下單。
              10. 1.3 出現(xiàn)的背景

                那么早期的微服務(wù)架構(gòu),面對(duì)這樣的情況的處理方式,出現(xiàn)了如下圖所示的調(diào)用方式。

                在這種調(diào)用方式中,不難發(fā)現(xiàn)問題會(huì)比較多:

              11. 客戶端和內(nèi)部微服務(wù)的耦合度較高,任何一邊發(fā)生變化,都會(huì)對(duì)另外一邊造成影響
              12. 客戶端需要維護(hù)內(nèi)部微服務(wù)的地址等信息,如果微服務(wù)地址發(fā)生變化也會(huì)影響客戶端的通信
              13. 客戶端需要調(diào)用多次接口請(qǐng)求,造成服務(wù)端請(qǐng)求過多
              14. 這種方式存在較多的問題,所以一般我們會(huì)在客戶端與微服務(wù)之間引入BFF層(即 Backend For Frontend(服務(wù)于前端的后端)),也就是服務(wù)器設(shè)計(jì)API時(shí)會(huì)考慮前端的使用,并在服務(wù)端直接進(jìn)行業(yè)務(wù)邏輯的處理,又稱為用戶體驗(yàn)適配器。

                如下圖所示,BFF層為客戶端提供了統(tǒng)一的聚合服務(wù),我們可以在BFF層為不同的端或者不同的業(yè)務(wù)提供更加友好和統(tǒng)一的客戶端。

                引入BFF層的好處是

              15. 客戶端和內(nèi)部微服務(wù)之間不存在之間耦合,使得兩端的變化可以獨(dú)立
              16. 當(dāng)APP端有新的需求時(shí),可以通過BFF層進(jìn)行評(píng)比,減少后端團(tuán)隊(duì)的溝通成本,如果后端微服務(wù)設(shè)計(jì)得足夠好的話,很多的需求在BFF層就可以搞定。
              17. 但是這種方式仍然存在問題,客戶端發(fā)起請(qǐng)求進(jìn)入到BFF層時(shí),需要考慮到安全問題,需要做鑒權(quán)、限流等,而這些功能需要在每一個(gè)BFF模塊中都需要編寫,增加了很多的重復(fù)代碼,而且維護(hù)起來非常不靈活導(dǎo)致開發(fā)效率下降。

                所以,引入了API網(wǎng)關(guān),整體結(jié)構(gòu)如下圖所示

                網(wǎng)關(guān)是微服務(wù)架構(gòu)不可或缺的一部分,作為微服務(wù)架構(gòu)的唯一入口,將所有請(qǐng)求轉(zhuǎn)發(fā)到后端對(duì)應(yīng)的微服務(wù)上去,同時(shí)又可以將各個(gè)微服務(wù)中的通用功能集中到網(wǎng)關(guān)去做,而不是在每個(gè)微服務(wù)都實(shí)現(xiàn)一遍,

              18. 身份驗(yàn)證和授權(quán)
              19. 限流
              20. 版本控制
              21. 緩存
              22. 統(tǒng)一日志
              23. 同時(shí),增加網(wǎng)關(guān)后,把各個(gè)BFF模塊的橫切功能剝離到網(wǎng)關(guān)中,BFF模塊開發(fā)人員只需要關(guān)注在業(yè)務(wù)邏輯的交付上。

                常見的開源網(wǎng)關(guān)

              24. OpenResty(Nginx+lua)
              25. Zuul,是spring cloud生態(tài)下提供的一個(gè)網(wǎng)關(guān)服務(wù),性能相對(duì)來說不是很高
              26. Spring Cloud Gateway,是Spring團(tuán)隊(duì)開發(fā)的高性能網(wǎng)關(guān)
              27. 1.4 Gateway簡(jiǎn)介

                Spring Cloud Gateway 是 Spring 官方團(tuán)隊(duì)研發(fā)的 API 網(wǎng)關(guān)技術(shù),它的目的是取代 Zuul 為微服務(wù)提供一種簡(jiǎn)單高效的 API 網(wǎng)關(guān)。一般來說,Spring 團(tuán)隊(duì)不會(huì)重復(fù)造輪子,為什么又研發(fā)出一個(gè) Spring Cloud Gateway 呢?有幾方面原因。

                • Zuul1.x 采用的是傳統(tǒng)的 thread per connection 方式來處理請(qǐng)求,也就是針對(duì)每一個(gè)請(qǐng)求,會(huì)為這個(gè)請(qǐng)求專門分配一個(gè)線程來進(jìn)行處理,直到這個(gè)請(qǐng)求完成之后才會(huì)釋放線程,一旦后臺(tái)服務(wù)器響應(yīng)較慢,就會(huì)使得該線程被阻塞,所以它的性能不是很好。
                • Zuul 本身存在的一些性能問題不適合于高并發(fā)的場(chǎng)景,雖然后來 Netflix 決定開發(fā)高性能版 Zuul 2.x,但是 Zuul 2.x 的發(fā)布時(shí)間一直不確定。雖然 Zuul 2.x 后來已經(jīng)發(fā)布并且開源了,但是 Spring Cloud 并沒有打算集成進(jìn)來。Spring Cloud Gateway 是依賴于 Spring Boot 2.0、Spring WebFlux 和 Project Reactor 等技術(shù)開發(fā)的網(wǎng)關(guān),它不僅提供了統(tǒng)一的路由請(qǐng)求的方式,還基于過濾鏈的方式提供了網(wǎng)關(guān)最基本的功能。

                1.5 Gateway基本概念

                Spring Cloud Gateway的基本工作原理如下圖所示。

                客戶端向Spring Cloud Gateway發(fā)出請(qǐng)求。然后在Gateway Handler Mapping中找到與請(qǐng)求相匹配的路由,將其發(fā)送到Gateway Web Handler。Handler 再通過指定的過濾器鏈來將請(qǐng)求發(fā)送到我們實(shí)際的服務(wù)執(zhí)行業(yè)務(wù)邏輯,然后返回。

                過濾器之間用虛線分開是因?yàn)檫^濾器可能會(huì)在發(fā)送代理請(qǐng)求之前(“pre”)或之后(“post”)執(zhí)行業(yè)務(wù)邏輯。

                • Filter在“pre”類型的過濾器可以做參數(shù)校驗(yàn)、權(quán)限校驗(yàn)、流量監(jiān)控、日志輸出、協(xié)議轉(zhuǎn)換等,
                • 在“post”類型的過濾器中可以做響應(yīng)內(nèi)容、響應(yīng)頭的修改,日志的輸出,流量監(jiān)控等有著非常重要的作用。

                在Spring Cloud Gateway中有三個(gè)重要的對(duì)象,分別是:

                • Route路由,它是網(wǎng)關(guān)的基礎(chǔ)元素,包含ID、目標(biāo)URI、斷言、過濾器組成,當(dāng)前請(qǐng)求到達(dá)網(wǎng)關(guān)時(shí),會(huì)通過Gateway Handler Mapping,基于斷言進(jìn)行路由匹配,當(dāng)斷言為true時(shí),匹配到路由進(jìn)行轉(zhuǎn)發(fā)
                • Predicate斷言,學(xué)過java8的同學(xué)應(yīng)該知道這個(gè)函數(shù),它可以允許開發(fā)人員去匹配HTTP請(qǐng)求中的元素,一旦匹配為true,則表示匹配到合適的路由進(jìn)行轉(zhuǎn)發(fā)
                • Filter過濾器,可以在請(qǐng)求發(fā)出的前后進(jìn)行一些業(yè)務(wù)上的處理,比如授權(quán)、埋點(diǎn)、限流等。

                具體的工作原理如下圖所示:

                它的整體工作原理如下。

                其中,predicate就是我們的匹配條件;而filter,就可以理解為一個(gè)無(wú)所不能的攔截器。有了這兩個(gè)元素,再加上目標(biāo)uri,就可以實(shí)現(xiàn)一個(gè)具體的路由了。

                客戶端向 Spring Cloud Gateway 發(fā)出請(qǐng)求,如果請(qǐng)求與網(wǎng)關(guān)程序定義的路由匹配,則該請(qǐng)求就會(huì)被發(fā)送到網(wǎng)關(guān) Web 處理程序,此時(shí)處理程序運(yùn)行特定的請(qǐng)求過濾器鏈。

                過濾器之間用虛線分開的原因是過濾器可能會(huì)在發(fā)送代理請(qǐng)求的前后執(zhí)行邏輯。所有 pre 過濾器邏輯先執(zhí)行,然后執(zhí)行代理請(qǐng)求;代理請(qǐng)求完成后,執(zhí)行 post 過濾器邏輯。

                第2章 Predicate應(yīng)用

                下面我們通過一些案例演示來初步了解Spring Cloug Gateway.

                1.在上文的基礎(chǔ)之上,整個(gè)項(xiàng)目拷貝過來,并改名為gateway-**

                2.在上面的框架基礎(chǔ)之上,修改user項(xiàng)目中的HelloController和UserController

                @RestControllerpublic class HelloController { @Autowired OrderServiceClient orderServiceClient; @Value(“${server.port}”) private int port; @GetMapping(“/hello/{name}”) public String get(@PathVariable(“name”) String name){ String result = “”; //同步 result = new HelloCommand(name,orderServiceClient).execute(); return “當(dāng)前user端口為:”+port+”,結(jié)果為:”+result; }}@RestControllerpublic class UserController { @Autowired OrderServiceClient orderServiceClient; @Value(“${server.port}”) private int port; @HystrixCommand(commandProperties = { @HystrixProperty(name=”circuitBreaker.requestVolumeThreshold”,value = “10”), @HystrixProperty(name=”circuitBreaker.sleepWindowInMilliseconds”,value=”5000″), @HystrixProperty(name=”circuitBreaker.errorThresholdPercentage”,value=”50″), },fallbackMethod = “fallback”) @GetMapping(“/get/{num}”) public String get(@PathVariable(“num”) int num){ if(num%2==0){ return “當(dāng)前user端口為:”+port+”,結(jié)果為:正常訪問”; } return “當(dāng)前user端口為:”+port+”,結(jié)果為:”+orderServiceClient.orderLists(num); } public String fallback(int num){ return “觸發(fā)降級(jí)”; }}

                并分別開啟兩個(gè)user項(xiàng)目,端口為8080和8081;開啟兩個(gè)order項(xiàng)目,端口分別為8088和8099

                3.創(chuàng)建新的springboot項(xiàng)目gateway-common

                4.配置pom

                4.0.0 eclipse2019-demo com.example 1.0-SNAPSHOT com.example gateway-common 0.0.1-SNAPSHOT gateway-common Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-test test org.springframework.cloud spring-cloud-starter-gateway org.springframework.cloud spring-cloud-starter-netflix-eureka-client

                5.配置yml,如果用的是nacos,一般這些配置可以寫在nacos里面

                server: port: 9527 spring: application: name: gateway cloud: gateway: routes: # 路由的ID,沒有固定規(guī)則但要求唯一,建議配合服務(wù)名 – id: getUser # 匹配后提供服務(wù)的路由地址 uri: http://localhost:8080 # 斷言,路徑相匹配的進(jìn)行路由 predicates: – Path=/get/** – id: sayHello uri: http://localhost:8081 predicates: – Path=/hello/** – id: heihei uri: https://www.baidu.com/ predicates: – Path=/heihei/** filters: – StripPrefix=1 #去掉地址中的第一部分 – StripPrefix=2 #去掉地址中的第二部分eureka: instance: hostname: gateway-9527 client: service-url: register-with-eureka: true fetch-registry: true defaultZone: http://127.0.0.1:8761/eureka

                6.啟動(dòng)類

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

                7.測(cè)試

                2.1 Predicate規(guī)則

                上述案例中,我們使用了Gateway中的 Path匹配規(guī)則,也就是根據(jù)請(qǐng)求的uri地址,使用前綴匹配規(guī)則完成請(qǐng)求地址的匹配。

                Gateway內(nèi)置了是多種Predicate匹配規(guī)則,具體如下圖所示

                2.1.1 Query斷言

                Query 路由斷言工廠接收兩個(gè)參數(shù),一個(gè)必需的參數(shù)和一個(gè)可選的正則表達(dá)式。

                spring: cloud: gateway: routes: – id: query_route uri: https://www.baidu.com/ predicates: – Query=name, eclipse2019.*shuai

                如果請(qǐng)求包含一個(gè)name的參數(shù),值是eclipse2019開頭,shuaiqi結(jié)尾,則此路由將匹配。第二個(gè)參數(shù)是正則表達(dá)式。

                測(cè)試鏈接:http://localhost:9527/?name=feichangshuaiqieclipse2019

                2.1.2 Method斷言

                Method 路由斷言工廠接收一個(gè)參數(shù),即要匹配的 HTTP 方法。

                spring: cloud: gateway: routes: – id: method_route uri: https://www.douyu.com/ predicates: – Method=GET

                2.1.3 Header斷言

                Header 路由斷言工廠接收兩個(gè)參數(shù),分別是請(qǐng)求頭名稱和正則表達(dá)式。

                spring: cloud: gateway: routes: – id: header_route uri: https://www.douyin.com/ predicates: – Header=X-Request-Id, d+

                如果請(qǐng)求中帶有請(qǐng)求頭名為 X-Request-Id,其值與 d+ 正則表達(dá)式匹配(值為一個(gè)或多個(gè)數(shù)字),則此路由匹配。

                2.1.4 Cookie斷言

                spring: cloud: gateway: routes: – id: cookie_route uri: https://www.huya.com/ predicates: – Cookie=name,eclipse2019

                通過postman,訪問http://localhost:9527 ; 并且在請(qǐng)求中攜帶cookie name=eclipse2019。 即可匹配到路由進(jìn)行轉(zhuǎn)發(fā)。

                2.2 自定義Predicate

                除了使用到官方提供的斷言工廠之外,如果我們有個(gè)性化的需求,也是可以實(shí)現(xiàn)自定義斷言工廠的。自定義路由斷言工廠需要繼承 AbstractRoutePredicateFactory 類,重寫 apply 方法的邏輯。在 apply 方法中可以通過 exchange.getRequest() 拿到 ServerHttpRequest 對(duì)象,從而可以獲取到請(qǐng)求的參數(shù)、請(qǐng)求方式、請(qǐng)求頭等信息。

                apply 方法的參數(shù)是自定義的配置類,在使用的時(shí)候配置參數(shù),在 apply 方法中直接獲取使用。

                命名需要以 RoutePredicateFactory 結(jié)尾,比如 AuthRoutePredicateFactory,那么在使用的時(shí)候Auth 就是這個(gè)路由斷言工廠的名稱。代碼如下所示。

                1.自定義AuthRoutePredicateFactory

                @Componentpublic class AuthRoutePredicateFactory extends AbstractRoutePredicateFactory{ Logger logger= LoggerFactory.getLogger(AuthRoutePredicateFactory.class); public static final String NAME_KEY = “name”; public AuthRoutePredicateFactory() { super(Config.class); } @Override public List shortcutFieldOrder() { return Arrays.asList(NAME_KEY); } @Override public Predicate apply(Config config) { logger.info(“AuthRoutePredicateFactory Start”); //只要請(qǐng)求的header中包含yml配置的Authorization,就允許匹配路由 return exchange -> { HttpHeaders headers=exchange.getRequest().getHeaders(); List header=headers.get(config.getName()); return header.size()>0; }; } public static class Config{ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }}

                2.在配置文件中添加如下配置信息

                – id: define_route uri: https://www.baidu.com predicates: – Path=/define/** – Auth=Authorization filters: – StripPrefix=1

                3.訪問測(cè)試

              28. postman中訪問url:http://localhost:9527/define/1測(cè)試: 在header中添加Authorization 以及不添加 Authorization的效果。
              29. 第3章 Filter應(yīng)用

                filter是網(wǎng)關(guān)中的核心,它起到了請(qǐng)求過濾的作用。在gateway中,會(huì)對(duì)請(qǐng)求做pre和post的過濾,pre表示請(qǐng)求進(jìn)來之前,post表示請(qǐng)求處理完成之后返回給客戶端之前。

                • pred類型的過濾器可以做授權(quán)認(rèn)證、流量監(jiān)控、協(xié)議轉(zhuǎn)化等工作
                • post過濾器可以做響應(yīng)內(nèi)容的修改、日志的輸出等。

                下圖表示的是請(qǐng)求和響應(yīng),經(jīng)過filter的處理流程。

                3.1 Filter分類

                在Spring Cloud Gateway中,F(xiàn)ilter按照作用范圍可以分為兩類

                全局過濾器,針對(duì)所有的請(qǐng)求都會(huì)被攔截

                局部過濾器,只針對(duì)某一個(gè)指定的route有效

                我們先來了解一下局部過濾器,在前面講Predicate的時(shí)候,其實(shí)已經(jīng)涉及到了Filter的使用。

                在Spring Cloud Gateway中,內(nèi)置了非常多的過濾器,如下圖所示

                3.2 常用Filter

                3.2.1 AddRequestParameter

                針對(duì)所有匹配的請(qǐng)求,添加一個(gè)查詢參數(shù)。

                下面這段配置,會(huì)針對(duì)所有請(qǐng)求增加一個(gè)tn=baiduimage&word=%E7%BE%8E%E5%A5%B3的參數(shù)

                spring: cloud: gateway: routes: – id: add_request_parameter_route uri: https://image.baidu.com/ predicates: – Path=/search/index/** filters: – AddRequestParameter=tn,baiduimage – AddRequestParameter=word,%E7%BE%8E%E5%A5%B3

                3.2.2 RequestRateLimiter

                該過濾器會(huì)對(duì)訪問到當(dāng)前網(wǎng)關(guān)的所有請(qǐng)求執(zhí)行限流過濾,如果被限流,默認(rèn)情況下會(huì)響應(yīng)HTTP 429-Too Many Requests。RequestRateLimiterGatewayFilterFactory 默認(rèn)提供了 RedisRateLimiter 的限流實(shí)現(xiàn),它采用令牌桶算法來實(shí)現(xiàn)限流功能

                spring: cloud: gateway: routes: – id: request_ratelimiter_route uri: https://www.taobao.com/ predicates: – Path=/tb/** filters: – StripPrefix=1 – name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 2 redis-rate-limiter.burstCapacity: 5 key-resolver: “#{@userkeyResolver}” #這個(gè)必須要配置,否則返回403

                redis-rate-limiter 過濾器有兩個(gè)配置屬性,如果大家了解令牌桶,就很容易知道它們的含義。

                • replenishRate:令牌桶中令牌的填充速度,代表允許每秒執(zhí)行的請(qǐng)求數(shù)。
                • burstCapacity:令牌桶的容量,也就是令牌桶最多能夠容納的令牌數(shù)。表示每秒用戶最大能夠執(zhí)行的請(qǐng)求數(shù)量。
                • key-resolver:關(guān)鍵字標(biāo)識(shí)的限流

                使用redis限流的話還要做一些事:

                1.pom中引包

                org.springframework.boot spring-boot-starter-data-redis-reactive

                2.設(shè)置redis的地址

                spring: redis: database: 1 password: eclipse2019 host: localhost

                3.在啟動(dòng)類或者配置類中加如下代碼

                @BeanKeyResolver userkeyResolver(){ //根據(jù)請(qǐng)求的ip進(jìn)行限流 return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());}

                3.2.3 Retry

                Retry GatewayFilter Factory 為請(qǐng)求重試過濾器,當(dāng)后端服務(wù)不可用時(shí),網(wǎng)關(guān)會(huì)根據(jù)配置參數(shù)來發(fā)起重試請(qǐng)求

                spring: cloud: gateway: routes: – id: retry_route uri: http://www.example.com predicates: – Path=/example/** filters: – name: Retry args: retries: 3 status: 503 – StripPrefix=1

                RetryGatewayFilter 提供 4 個(gè)參數(shù)來控制重試請(qǐng)求,參數(shù)說明如下。

                • retries:請(qǐng)求重試次數(shù),默認(rèn)值是 3。
                • status:HTTP 請(qǐng)求返回的狀態(tài)碼,針對(duì)指定狀態(tài)碼進(jìn)行重試,比如,在上述配置中,當(dāng)服務(wù)端返回的狀態(tài)碼是 503 時(shí),才會(huì)發(fā)起重試,此處可以配置多個(gè)狀態(tài)碼。
                • methods:指定 HTTP 請(qǐng)求中哪些方法類型需要進(jìn)行重試,默認(rèn)是 GET。
                • series:配置錯(cuò)誤碼段,表示符合某段狀態(tài)碼才發(fā)起重試,默認(rèn)值是 SERVER_ERROR(5),表示 5xx 段的狀態(tài)碼都會(huì)發(fā)起重試。如果 series 配置了錯(cuò)誤碼段,但是 status 沒有配置,則仍然會(huì)匹配 series 進(jìn)行重試。

                3.2.4 全局過濾器

                全局過濾器和GatewayFilter的作用是相同的,只是GlobalFilter針對(duì)所有的路由配置生效。Spring Cloud Gateway默認(rèn)內(nèi)置了一些全局過濾器

                • GatewayMetricsFilter,提供監(jiān)控指標(biāo)。
                • ReactiveLoadBalancerClientFilter,整合 Ribbon 針對(duì)下游服務(wù)實(shí)現(xiàn)負(fù)載均衡。
                • ForwardRoutingFilter,用于本地 forward,請(qǐng)求不轉(zhuǎn)發(fā)到下游服務(wù)器。
                • NettyRoutingFilter,使用 Netty 的 HttpClient 轉(zhuǎn)發(fā) HTTP、HTTPS 請(qǐng)求
                • ….

                全局過濾鏈的執(zhí)行順序是,當(dāng) Gateway 接收到請(qǐng)求時(shí),F(xiàn)iltering Web Handler 處理器會(huì)將所有的 GlobalFilter 實(shí)例及所有路由上所配置的 GatewayFilter 實(shí)例添加到一條過濾器鏈中。該過濾器鏈里的所有過濾器都會(huì)按照@Order 注解所指定的數(shù)字大小進(jìn)行排序。

                3.2.5 自定義過濾器

                雖然Spring Cloud Gateway提供了非常多的過濾器,但是在實(shí)際應(yīng)用中,我們必然會(huì)涉及到和業(yè)務(wù)有關(guān)的過濾器,比如日志記錄、鑒權(quán)、黑白名單等。Spring Cloud Gateway 提供了過濾器的擴(kuò)展功能,開發(fā)者可以根據(jù)實(shí)際業(yè)務(wù)需求來自定義過濾器,這樣我們就可以在網(wǎng)關(guān)層實(shí)現(xiàn)時(shí)鑒權(quán)、日志管理、協(xié)議轉(zhuǎn)化等功能。同樣,自定義過濾器也支持 GlobalFilter 和 GatewayFilter 兩種。

                3.2.5.1 自定義GatewayFilter

                首先創(chuàng)建一個(gè)自定義過濾器類MyDefineGatewayFilterFactory,繼承AbstractGatewayFilterFactory。

                @Componentpublic class MyDefineGatewayFilterFactory extends AbstractGatewayFilterFactory{ Logger logger= LoggerFactory.getLogger(MyDefineGatewayFilterFactory.class); public static final String NAME_KEY = “name”; public MyDefineGatewayFilterFactory() { super(MyConfig.class); } @Override public List shortcutFieldOrder() { return Arrays.asList(NAME_KEY); } @Override public GatewayFilter apply(MyConfig config) { return ((exchange, chain) -> { logger.info(“[Pre] Filter Request,name:”+config.getName()); //then接收一個(gè)變量,然后then前面處理的那個(gè)就結(jié)束了,后面開始處理then接收的這個(gè)變量 return chain.filter(exchange).then(Mono.fromRunnable(()->{ logger.info(“[Post] Response Filter”); })); }); } public static class MyConfig{ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }}

                在上述代碼中,有幾點(diǎn)需要注意:

                • 類名必須要統(tǒng)一以GatewayFilterFactory結(jié)尾,因?yàn)槟J(rèn)情況下過濾器的 name 會(huì)采用該自定義類的前綴。這里的 name=MyDefine。
                • 在apply方法中,同時(shí)包含Pre和Post過濾。在then方法中是請(qǐng)求執(zhí)行結(jié)束之后的后置處理。
                • MyConfig 是一個(gè)配置類,該類中只有一個(gè)屬性 name。這個(gè)屬性可以在 yml 文件中使用。
                • 該類需要裝載到 Spring IoC 容器,此處使用@Component注解實(shí)現(xiàn)。

                接下來,修改application.yml,增加自定義過濾器配置

                spring: cloud: gateway: routes: – id: define_route uri: http://localhost:8080 predicates: – Path=/define/** filters: – MyDefine=My_Eclipse2019

                此時(shí)訪問到這個(gè)過濾器,就會(huì)輸出如下日志,說明進(jìn)入到了網(wǎng)關(guān)攔截器。

                2020-06-02 22:08:21.838 INFO 164 — [ioEventLoop-5-2] c.e.s.MyDefineGatewayFilterFactory : [Pre] Filter Request,name:My_Eclipse20192020-06-02 22:08:21.875 INFO 164 — [ctor-http-nio-5] c.e.s.MyDefineGatewayFilterFactory : [Post] Response Filter

                3.2.5.2 自定義GlobalFilter

                GlobalFilter 的實(shí)現(xiàn)比較簡(jiǎn)單,它不需要額外的配置,只需要實(shí)現(xiàn) GlobalFilter 接口,自動(dòng)會(huì)過濾所有的 Route

                @Servicepublic class MyDefineFilter implements GlobalFilter,Ordered{ Logger log= LoggerFactory.getLogger(MyDefineFilter.class); @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { log.info(“[pre]-Enter MyDefineFilter”); return chain.filter(exchange).then(Mono.fromRunnable(()->{ log.info(“[post]-Return Result”); })); } @Override public int getOrder() { return 0; }}

                getOrder 表示該過濾器的執(zhí)行順序,值越小,執(zhí)行優(yōu)先級(jí)越高。需要注意的是,我們通過 AbstractGatewayFilterFactory 實(shí)現(xiàn)的局部過濾器沒有指定 order,它的默認(rèn)值是 0,如果想要設(shè)置多個(gè)過濾器的執(zhí)行順序,可以重寫 getOrder 方法。

                第4章 路由

                4.1 基于集群負(fù)載均衡路由

                當(dāng)被路由的目標(biāo)服務(wù)是一個(gè)集群節(jié)點(diǎn)時(shí),就會(huì)涉及到集群路由,Spring Cloud Gateway提供了一個(gè)LoadBalancerClientFilter全局過濾器,來實(shí)現(xiàn)負(fù)載均衡的解析。

                1.增加jar包依賴

                org.springframework.cloud spring-cloud-starter-netflix-eureka-client

                2.user項(xiàng)目也要注冊(cè)到Eureka上面去

                3.修改application.yml配置

                spring: application: name: gateway redis:database: 1 password: eclipse2019 host: localhost cloud: gateway: routes: – id: getUser uri: lb://user # 修改這里 predicates: – Path=/get/** discovery: # 修改這里 locator: enabled: true lower-case-service-id: true server: port: 9527eureka: # 修改這 instance: hostname: gateway-9527 client: service-url: register-with-eureka: true fetch-registry: true defaultZone: http://127.0.0.1:8761/eureka

                增加部分的配置說明如下

                • lower-case-service-id:是否使用 service-id 的小寫,默認(rèn)是大寫。
                • spring.cloud.gateway.discovery.locator.enabled:開啟從注冊(cè)中心動(dòng)態(tài)創(chuàng)建路由的功能。
                • uri 中配置的lb://表示從注冊(cè)中心獲取服務(wù),后面的user表示目標(biāo)服務(wù)在注冊(cè)中心上的服務(wù)名

                重啟gateway-common項(xiàng)目,訪問:http://localhost/get/3接口。

                4.2 動(dòng)態(tài)路由的實(shí)現(xiàn)

                在實(shí)際應(yīng)用中, 我們還會(huì)存在一種:動(dòng)態(tài)配置路由的需求。也就是在運(yùn)行過程中,動(dòng)態(tài)增加或者修改網(wǎng)關(guān)路由配置,這個(gè)需求在Spring Cloud Gateway中如何實(shí)現(xiàn)呢?

                在Spring Cloud Gateway中,提供了GatewayControllerEndpoint這個(gè)類來實(shí)現(xiàn)路由的動(dòng)態(tài)修改,可以通過actuator打開這些endpoint信息

                1.添加Pom依賴

                org.springframework.boot spring-boot-starter-actuator

                2.修改application.yml,開發(fā)所有endpoint

                management: endpoints: web: exposure: include: *

                4.2.1 檢索網(wǎng)關(guān)中定義的路由

                通過這個(gè)地址:http://localhost:9527/actuator/gateway/routes可以獲得當(dāng)前網(wǎng)關(guān)中所有定義的路由

                [ { predicate: “Paths: [/get/**], match trailing slash: true”, route_id: “getUser”, filters: [ ], uri: “lb://user”, order: 0, }]

                其中:

                • route_id 表示路由編號(hào)
                • route_object.predicate 表示路由的條件匹配謂詞
                • route_object.filters 表示網(wǎng)關(guān)過濾器
                • order 路由順序

                4.2.2 查找特定的路由信息。

                http://localhost:9527/actuator/gateway/routes/{route_id}

                4.2.3 刷新路由緩存

                {POST請(qǐng)求}http://localhost:9527/actuator/gateway/refresh

                4.2.4 增減、修改路由

                /gateway/routes/{id} @PostMapping 新增一個(gè)路由信息

                /gateway/routes/{id} @DeleteMapping 刪除一個(gè)路由信息

                1.案例演示(添加路由)

                • 通過POST請(qǐng)求添加一個(gè)路由信息,http://localhost:9527/actuator/gateway/routes/baidu_route

                { “uri”: “https://www.baidu.com”, “predicates”: [{ “args”: { “pattern”: “/baidu/**” }, “name”: “Path” }], “filters”: [{ “args”: { “_genkey_0”: 1 }, “name”: “StripPrefix” }]}

                • 執(zhí)行:{POST請(qǐng)求}http://localhost:9527/actuator/gateway/refresh刷新路由。
                • 通過訪問:http://localhost:9527/actuator/gateway/routes 查看當(dāng)前路由列表,可以發(fā)現(xiàn)多了一個(gè)段這樣的內(nèi)容。

                { predicate: “Paths: [/baidu/**], match trailing slash: true”, route_id: “baidu_route”, filters: [ “[[StripPrefix parts = 1], order = 1]” ], uri: “https://www.baidu.com:443”, order: 0,}

                • 此時(shí)我們?cè)L問: http://localhost:9527/baidu ,就會(huì)路由到百度搜索引擎這個(gè)網(wǎng)址。

                2.案例演示(刪除路由)

                • 通過/gateway/routes/{id} @DeleteMapping 刪除一個(gè)路由信息
                • 通過postman調(diào)用 /gateway/routes/baidu_route (delete請(qǐng)求), 就可以刪除路由,刪除路由之后再次訪問路由列表頁(yè)面,此時(shí)可以發(fā)現(xiàn)路由信息是被刪除的。

                4.2.5 小結(jié)

                基于Spring Cloud Gateway默認(rèn)方法實(shí)現(xiàn)的動(dòng)態(tài)路由就講解完了,但是通過這種形式是去更新的動(dòng)態(tài)路由信息,是基于內(nèi)存來實(shí)現(xiàn)的。一旦服務(wù)重啟,新增的路由配置信息就會(huì)全部清空,所以這個(gè)時(shí)候我們可以參考GatewayControllerEndpoint這個(gè)類,來自己實(shí)現(xiàn)一套動(dòng)態(tài)路由的方法。并且將路由信息持久化。

                在實(shí)際開發(fā)中也可以通過Nacos作為配置中心直接在Nacos上面增加。

                下文預(yù)告

              30. Gateway核心源碼分析
              31. 鄭重聲明:本文內(nèi)容及圖片均整理自互聯(lián)網(wǎng),不代表本站立場(chǎng),版權(quán)歸原作者所有,如有侵權(quán)請(qǐng)聯(lián)系管理員(admin#wlmqw.com)刪除。
                用戶投稿
                上一篇 2022年7月11日 09:33
                下一篇 2022年7月11日 09:33

                相關(guān)推薦

                聯(lián)系我們

                聯(lián)系郵箱:admin#wlmqw.com
                工作時(shí)間:周一至周五,10:30-18:30,節(jié)假日休息