SpringCloud入門(mén)實(shí)戰(zhàn)- Gateway服務(wù)網(wǎng)關(guān)

?? 《SpringCloud入門(mén)實(shí)戰(zhàn)系列》解鎖SpringCloud主流組件入門(mén)應(yīng)用及關(guān)鍵特性。帶你了解SpringCloud主流組件,是如何一戰(zhàn)解決微服務(wù)諸多難題的。項(xiàng)目demo:源碼地址

一、Gateway是什么?

Gateway關(guān)鍵特性:路由、斷言、過(guò)濾。

Spring Cloud Gateway是 Spring Cloud 的一個(gè)全新項(xiàng)目,基于 Spring 6.0+Spring Boot 3.0和 Project Reactor 等技術(shù)開(kāi)發(fā)的網(wǎng)關(guān),它旨在為微服務(wù)架構(gòu)提供一種簡(jiǎn)單有效的統(tǒng)一的 API路由管理方式。

Spring Cloud Gateway 作為 Spring Cloud 生態(tài)系統(tǒng)中的網(wǎng)關(guān),目標(biāo)是替代Zuul。

Cloud全家桶中有個(gè)很重要的組件就是網(wǎng)關(guān),在1.x版本中都是采用的Zuul網(wǎng)關(guān),在SpringCloud Finchley 正版之前,Spring Cloud 推薦的網(wǎng)關(guān)是 Netflix 提供的Zuul,但在2.x版本中,SpringCloud最后自己研發(fā)了一個(gè)網(wǎng)關(guān)Gateway替代Zuul。

在Spring Cloud 2.0以上版本中,沒(méi)有對(duì)新版本Zuul2.0以最新高性能版本進(jìn)行集成,仍然還是使用的Zuul 1.x非Reactor模式的老版本。而為了提升網(wǎng)關(guān)的性能,SpringCloud gateway,其于WebFlux框架實(shí)現(xiàn)的,而WebFlux框架底層,則使用了高性能的Reactor模式通訊框架Nettey。

Spring Cloud Gateway的目標(biāo)提供統(tǒng)一的路由方式且基于 Filter 鏈的方式提供了網(wǎng)關(guān)基本的功能,例如: 安全,監(jiān)控/指標(biāo),和限流。

Spring WebFlux 是 Spring 5.0 引入的新的響應(yīng)式框架,區(qū)別于 Spring MVC,它不需要依賴(lài)Servlet API,它是完全異步非阻塞的,并且基于 Reactor 來(lái)實(shí)現(xiàn)響應(yīng)式流規(guī)范。
Spring WebFlux官網(wǎng)信息

二、Spring Cloud Gateway 與 Zuul的區(qū)別(選型問(wèn)題)

1、Zuul 1.x,是個(gè)其于阻塞I /O的API Gateway

2、Zuul 1.x 基于Sevlet 2.5使用阻塞架構(gòu)。它不支持任何長(zhǎng)連接(如 WebSocket) Zuul 的設(shè)計(jì)模式和Nginx較像,每次 I /O操作都是從工作線程中選擇一個(gè)執(zhí)行,請(qǐng)求線程被阻塞到工作線程完成,但是差別是Nginx 用C++ 實(shí)現(xiàn),Zuul 用Java 實(shí)現(xiàn),而 JVM 本身會(huì)有第一次加載較慢的情況,便得Zuul 的性能相對(duì)較差。

3、Zuul 2.x理念更先進(jìn),想基于Netty非阻塞和支持長(zhǎng)連接,SpringCloud目前還沒(méi)有整合。Zuul 2.x的性能較 Zuul 1.x 有較大提在性能方面,根據(jù)官方提供的基準(zhǔn)測(cè)試,Spring Cloud Gateway 的 RPS (每秒請(qǐng)求數(shù)) 是Zuul的1.6倍。

4、Spring Cloud Gateway 建立在 Spring Framework 6、 Project Reactor 和 Spring Boot 3之上,使用非阻塞API。Gateway是基于異步非阻塞模型上進(jìn)行開(kāi)發(fā)的,所以性能好,雖然Netflex發(fā)布了最新的Zuul2,但SpringCloud沒(méi)有整合的計(jì)劃。

5、Spring Cloud Gateway還支持 WebSocket,并目與Spring緊密集成擁有更好的開(kāi)發(fā)體驗(yàn)。

6、通過(guò)官網(wǎng)可知:Zuul1.0已經(jīng)進(jìn)入了維護(hù)階段,而Gateway是SpringCloud團(tuán)隊(duì)研發(fā)的,值得信賴(lài)。

Netflex 公司的zuul,官網(wǎng)地址:zuul官網(wǎng)

Spring社區(qū)的Gateway,官網(wǎng)地址:Gateway官網(wǎng)。

兩者都是網(wǎng)關(guān)。Netflex 的zuul本來(lái)要升級(jí),核心人員跳槽了,另一方面zuul升級(jí)到zuul2分歧大,導(dǎo)致zuul不維護(hù)了,zuul2研發(fā)中,于是等不及了,Spring社區(qū)出現(xiàn)了新一代網(wǎng)關(guān)技術(shù)Gateway,所以我們接下來(lái)主要學(xué)習(xí)Gateway。

三、Spring Cloud Gateway特性

通過(guò)官網(wǎng)可知,Spring Cloud Gateway有如下特性:

  • (3.x版本以下)基于Spring Framework5,Project Reactor和 Spring Boot 2.0進(jìn)行構(gòu)建;
    (目前最高版本4.x版本)基于Spring Framework6,Project Reactor和 Spring Boot 3.0進(jìn)行構(gòu)建;
  • 動(dòng)態(tài)路由:能夠匹配任何請(qǐng)求屬性;
  • 可以對(duì)路由指定Predicate(斷言)和Filter(過(guò)濾器);
  • 集成Hystrix的斷路器功能;
  • 集成Spring Cloud服務(wù)發(fā)現(xiàn)功能;
  • 易于編寫(xiě)的Predicate(斷言)和Filter(過(guò)濾器);
  • 請(qǐng)求限流功能;
  • 支持路徑重寫(xiě);

四、Gateway三大概念與工作流程

1、重要概念(路由、斷言、過(guò)濾)

1)Route(路由):
路由是構(gòu)建網(wǎng)關(guān)的基本模塊,由ID,目標(biāo)URI,一系列的斷言和過(guò)濾器組成,如果斷言為true,則匹配該路由。

2)Predicate(斷言):
參考java8的java.util.function.Predicate開(kāi)發(fā)人員可以匹配HTTP請(qǐng)求中的所有內(nèi)容(例如請(qǐng)求頭、請(qǐng)求參數(shù)),如果請(qǐng)求與斷言相匹配則進(jìn)行路由。

3)Filter(過(guò)濾)
指的是由Spring框架中GatewayFilter實(shí)例,使用過(guò)濾器,可以在請(qǐng)求被路由之前或者之后對(duì)請(qǐng)求進(jìn)行修改。



web請(qǐng)求,通過(guò)一些匹配條件,定位到真正的服務(wù)節(jié)點(diǎn)。并在這個(gè)轉(zhuǎn)發(fā)過(guò)程的前和后,通過(guò)Filter進(jìn)行一些精細(xì)化控制和管理,predicate就是我們的匹配條件,有了這兩個(gè)元素,再加上目標(biāo)uri,就可以實(shí)現(xiàn)一個(gè)具體的路由了。

2、工作流程(核心:路由轉(zhuǎn)發(fā)+執(zhí)行過(guò)濾鏈)

從官網(wǎng)工作流程圖可知:客戶向 Spring Cloud Gateway 發(fā)出請(qǐng)求,然后在 Gateway Handler Mapping 中找到與請(qǐng)求相匹配的路由,將其發(fā)送到GatewayWeb Handler。

Handler 再通過(guò)指定的過(guò)濾器鏈來(lái)將請(qǐng)求發(fā)這到我們實(shí)際的服務(wù)執(zhí)行業(yè)務(wù)邏輯,然后返回。
過(guò)濾器之間用虛線分開(kāi)是因?yàn)檫^(guò)濾器可能會(huì)在發(fā)送代理請(qǐng)求之前 (“pre”) 或之后(“post”) 執(zhí)行業(yè)務(wù)邏輯。

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

五、Gateway項(xiàng)目集成與配置

具體項(xiàng)目集成可查看:SpringCloud Gateway網(wǎng)關(guān)項(xiàng)目集成與配置

六、Gateway動(dòng)態(tài)路由

默認(rèn)情況下Gateway會(huì)根據(jù)注冊(cè)中心注冊(cè)的服務(wù)列表,以注冊(cè)中心上微服務(wù)名為路徑創(chuàng)建動(dòng)態(tài)路由進(jìn)行轉(zhuǎn)發(fā),從而實(shí)現(xiàn)動(dòng)態(tài)路由的功能。

1、配置文件增加開(kāi)啟路由的配置

 discovery:
        locator:
          enabled: true #開(kāi)啟從注冊(cè)中心動(dòng)態(tài)創(chuàng)建路由的功能,利用微服務(wù)名進(jìn)行路由

2、將之前寫(xiě)死的uri換成微服務(wù)名稱(chēng)(注冊(cè)中心上顯示的服務(wù)名)

 uri: lb://cloud-payment #匹配后提供服務(wù)的路由地址

需要注意的是uri的協(xié)議為lb,表示啟用Gateway的負(fù)載均衡功能。
lb://serviceName是spring cloudgateway在微服務(wù)中自動(dòng)為我們創(chuàng)建的負(fù)載均衡uri

完整配置:

server:
  port: 9527

spring:
  application:
    name: cloud-gateway #微服務(wù)應(yīng)用的名字
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #開(kāi)啟從注冊(cè)中心動(dòng)態(tài)創(chuàng)建路由的功能,利用微服務(wù)名進(jìn)行路由
      routes:
        - id: payment_routh #payment_route    #路由的ID,沒(méi)有固定規(guī)則但要求唯一,建議配合服務(wù)名
          uri: lb://cloud-payment #匹配后提供服務(wù)的路由地址
          predicates:
            - Path=/payment/timeout/**        # 斷言,路徑相匹配的進(jìn)行路由
        - id: payment_routh2 #payment_route    #路由的ID,沒(méi)有固定規(guī)則但要求唯一,建議配合服務(wù)名
          uri: lb://cloud-payment #匹配后提供服務(wù)的路由地址
          predicates:
            - Path=/payment/ok/**         # 斷言,路徑相匹配的進(jìn)行路由
eureka:
  client:
    register-with-eureka: true #向注冊(cè)中心注冊(cè)自己
    fetch-registry: true #從EurekaServer抓取已有的注冊(cè)信息,集群必須設(shè)置成true,才能配合ribbon負(fù)載均衡
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka
  instance:
    instance-id: gateway9527 #主機(jī)名稱(chēng)修改
    prefer-ip-address: true #訪問(wèn)路徑可以顯示ip
    hostname: cloud-gateway-service

測(cè)試負(fù)載均衡效果, 8001/8002兩個(gè)端口切換。

七、Gateway的Predicate

1、網(wǎng)關(guān)項(xiàng)目啟動(dòng)時(shí),控制臺(tái)可以看到有很多種類(lèi)型的斷言。我們上邊演示的是Path類(lèi)型。


Spring Cloud Gateway包括許多內(nèi)置的Route Predicate工廠。
所有這些Predicate都與HTTP請(qǐng)求的不同屬性匹配。多個(gè)Route Predicate工廠可以進(jìn)行組合。
Spring Cloud Gateway 創(chuàng)建 Route 對(duì)象時(shí), 使用 RoutePredicateFactory 創(chuàng)建 Predicate 對(duì)象,Predicate 對(duì)象可以賦值給 Route。

2、 具體各種斷言配置參考官網(wǎng)示例:


3、演示一種,以After為例:

//官網(wǎng)上美國(guó)時(shí)間,我們獲取當(dāng)前時(shí)間:
 public static void main(String[] args) {
        ZonedDateTime obj=ZonedDateTime.now();
        System.out.println(obj);
  }
輸出:2023-06-06T15:36:36.892+08:00[Asia/Shanghai]
spring:
  application:
    name: cloud-gateway #微服務(wù)應(yīng)用的名字
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #開(kāi)啟從注冊(cè)中心動(dòng)態(tài)創(chuàng)建路由的功能,利用微服務(wù)名進(jìn)行路由
      routes:
        - id: payment_routh #payment_route    #路由的ID,沒(méi)有固定規(guī)則但要求唯一,建議配合服務(wù)名
          uri: lb://cloud-payment #匹配后提供服務(wù)的路由地址
          predicates:
            - Path=/payment/timeout/**        # 斷言,路徑相匹配的進(jìn)行路由
            - After=2023-06-06T15:36:36.892+08:00[Asia/Shanghai] #
        - id: payment_routh2 #payment_route    #路由的ID,沒(méi)有固定規(guī)則但要求唯一,建議配合服務(wù)名
          uri: lb://cloud-payment #匹配后提供服務(wù)的路由地址
          predicates:
            - Path=/payment/ok/**         # 斷言,路徑相匹配的進(jìn)行路由

After斷言表示:在這個(gè)時(shí)間后,請(qǐng)求才有效果,在這個(gè)時(shí)間前,請(qǐng)求會(huì)404

八、Gateway的Filter

1、過(guò)濾器查看官網(wǎng),37種之多(不常用)

參照官網(wǎng)添加相應(yīng)的filters標(biāo)簽配置即可:

spring:
  cloud:
    gateway:
      routes:
      - id: add_request_header_route
        uri: https://example.org
        filters:
        - AddRequestHeader=X-Request-red, blue

2、查看官網(wǎng),自定義過(guò)濾器10種之多(比較常用)


自定義全局GlobalFilter主要用于全局日志記錄、統(tǒng)一網(wǎng)關(guān)鑒權(quán)等。
實(shí)現(xiàn)兩個(gè)重要接口 GlobalFilter,Ordered,容器注入,即可。

代碼示例:

package com.qytest.springcloud.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Date;
@Component
@Slf4j
public class LogFilter implements GlobalFilter, Ordered {

    @Bean
    public GlobalFilter customFilter() {
        return new LogFilter();
    }
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("start global filter" + new Date());
        //假設(shè)請(qǐng)求參數(shù)沒(méi)有username認(rèn)為非法用戶,打印在日志中
        String username = exchange.getRequest().getQueryParams().getFirst("username");
        if (username == null) {
            System.out.println("username 為空,非法用戶!");
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -1;
    }
}


測(cè)試訪問(wèn)(不帶username):http://localhost:9527/payment/ok/1

?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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