1. 程式人生 > 實用技巧 >08.SpringCloud Gateway (新一代閘道器)

08.SpringCloud Gateway (新一代閘道器)

1.概述

基本說明

官網上一代閘道器 zuulhttps://github.com/Netflix/zuul/wiki 當前gatewayhttps://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/
是什麼
一句話Spring Cloud Gateway 使用的Webflux中的reactor-netty響應式程式設計元件,底層使用了Netty通訊框架原始碼架構
能幹嘛
  • 反向代理
  • 鑑權
  • 流量控制
  • 熔斷
  • 日誌監控

微服務架構中閘道器在哪裡有了Zuul了怎麼又出來了gateway

我們為什麼選擇Gatway?

  • 1.neflix不太靠譜,zuul2.0一直跳票,遲遲不釋出

  • 2.SpringCloud Gateway具有如下特性

  • 3.SpringCloud Gateway與Zuul的區別

Zuul1.x模型

GateWay模型

WebFlux是什麼?
說明

2.三大核心概念

Route(路由)

路由是構建閘道器的基本模組,它由ID,目標URI,一系列的斷言和過濾器組成,如果斷言為true則匹配該路由

Predicate(斷言)

參考的是java8的java.util.function.Predicate開發人員可以匹配HTTP請求中的所有內容(例如請求頭或請求引數),如果請求與斷言相匹配則進行路由

Filter(過濾)

指的是Spring框架中GatewayFilter的例項,使用過濾器,可以在請求被路由前或者之後對請求進行修改。
總體

3.Gateway工作流程

官網總結核心邏輯
  • 路由轉發+執行過濾器鏈

4.入門配置

新建模組cloud-gateway-gateway9527pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud2020</artifactId>
        <groupId>com.chl.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-gateway-gateway9527</artifactId>

    <dependencies>
        <!--新增gateway-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>com.chl.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>


</project>
yml
server:
  port: 9527
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true  #開啟從註冊中心動態建立路由的功能,利用微服務名進行路由
      routes:
        - id: payment_routh #路由的ID,沒有固定規則但要求唯一,建議配合服務名
          uri: http://localhost:8001   #匹配後提供服務的路由地址
          predicates:
            - Path=/payment/get/**   #斷言,路徑相匹配的進行路由

        - id: payment_routh2
          uri: http://localhost:8001   #匹配後提供服務的路由地址
          predicates:
            - Path=/payment/lb/**   #斷言,路徑相匹配的進行路由
         
eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka
主啟動類
@SpringBootApplication
@EnableEurekaClient
public class GateWayMain9527 {
    public static void main(String[] args) {
            SpringApplication.run( GateWayMain9527.class,args);
        }
}
9527閘道器如何做路由對映那???cloud-provider-payment8001看看controller的訪問地址 get個lb我們目前不想暴露8001埠,希望在8001外面套一層9527yml新增閘道器配置
server:
  port: 9527
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true  #開啟從註冊中心動態建立路由的功能,利用微服務名進行路由
      routes:
        - id: payment_routh #路由的ID,沒有固定規則但要求唯一,建議配合服務名
          uri: http://localhost:8001   #匹配後提供服務的路由地址
          predicates:
            - Path=/payment/get/**   #斷言,路徑相匹配的進行路由

        - id: payment_routh2
          uri: http://localhost:8001   #匹配後提供服務的路由地址
          predicates:
            - Path=/payment/lb/**   #斷言,路徑相匹配的進行路由
         
eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka
測試1.啟動70012.啟動8001 cloud-provider-payment80013.啟動9527閘道器4.訪問說明
  • 新增閘道器前
http://localhost:8001/payment/get/31
  • 新增閘道器前
http://localhost:9527/payment/get/31

yml配置說明

Gateway閘道器路由有兩種配置方式

在配置檔案yml中配置

見前面步驟

程式碼中注入RouteLocator的Bean

官網案例
百度國內新聞網址,需要外網http://news.baidu.com/guoji
自己寫一個測試下 百度新聞業務需求通過9527閘道器訪問到外網的百度新聞網址編碼 cloud-gateway-gateway9527實現業務新增配置bean
@Configuration
public class GateWayConfig {

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder) {
        RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
        routes.route("path_rote_atguigu", r -> r.path("/guonei").uri("http://news.baidu.com/guonei")).build();
        return routes.build();
    }
}

5.通過微服務名實現動態路由

預設情況下Gateway會根據註冊中心的服務列表,以註冊中心上微服務名為路徑建立動態路由進行轉發,從而實現動態路由的功能一個eureka7001+兩個服務提供者8001/8002

yml配置

需要注意的是uri的協議為lb,表示啟用Gateway的負載均衡功能。lb://serviceName是spring cloud gateway在微服務中自動為我們建立的負載均衡uri
server:
  port: 9527
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true  #開啟從註冊中心動態建立路由的功能,利用微服務名進行路由
      routes:
        - id: payment_routh #路由的ID,沒有固定規則但要求唯一,建議配合服務名
          #uri: http://localhost:8001   #匹配後提供服務的路由地址
          uri: lb://cloud-payment-service  #負載均衡,根據服務名找
          predicates:
            - Path=/payment/get/**   #斷言,路徑相匹配的進行路由

        - id: payment_routh2
          #uri: http://localhost:8001   #匹配後提供服務的路由地址
          uri: lb://cloud-payment-service  #負載均衡,根據服務名找
          predicates:
            - Path=/payment/lb/**   #斷言,路徑相匹配的進行路由
  
eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka
測試http://localhost:9527/payment/lb 8001/8002兩個埠切換

6.Predicate的使用

是什麼

啟動我們的gatewat9527
Route Predicate Factories這個是什麼東東?

常用的Route Predicate


1.After Route Predicateyml配置
            #這些是常用的斷言,如果不符合,就返回404,找不到
            - After=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]  這個時間後面訪問才行

2.Before Route Predicate
         - Before=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]  

3.Between Route Predicate
         - Between=2020-03-08T10:59:34.102+08:00[Asia/Shanghai] ,  2020-03-08T10:59:34.102+08:00[Asia/Shanghai]

4. Cookie Route Predicate不帶cookies訪問帶上cookies訪問 加入curl返回中文亂碼 https://blog.csdn.net/leedee/article/details/82685636
  - Cookie=username,atguigu    #並且Cookie是username=zhangshuai才能訪問

5. Header Route Predicate
6.Host Route Predicate
  - Host=**.baidu.com

7.Method Route Predicate
    - Method=GET

8.Path Route Predicate
9. Query Route Predicate
 - Query=username, \d+ #要有引數名稱並且是正整數才能路由

10.小總結說白了,Predicate就是為了實現一組匹配規則,讓請求過來找到對應的Route進行處理
server:
  port: 9527
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true  #開啟從註冊中心動態建立路由的功能,利用微服務名進行路由
      routes:
        - id: payment_routh #路由的ID,沒有固定規則但要求唯一,建議配合服務名
          #uri: http://localhost:8001   #匹配後提供服務的路由地址
          uri: lb://cloud-payment-service  #負載均衡,根據服務名找
          predicates:
            - Path=/payment/get/**   #斷言,路徑相匹配的進行路由

        - id: payment_routh2
          #uri: http://localhost:8001   #匹配後提供服務的路由地址
          uri: lb://cloud-payment-service  #負載均衡,根據服務名找
          predicates:
            - Path=/payment/lb/**   #斷言,路徑相匹配的進行路由
            #這些是常用的斷言,如果不符合,就返回404,找不到
            #- After=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]  這個時間後面訪問才行
            #- Cookie=username,zhangshuai #並且Cookie是username=zhangshuai才能訪問
            #- Header=X-Request-Id, \d+ #請求頭中要有X-Request-Id屬性並且值為整數的正則表示式
            #- Host=**.atguigu.com #主機攜帶是這個才行
            #- Method=GET    #get 方法訪問
            #- Query=username, \d+ #要有引數名稱並且是正整數才能


eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka

7.Filter的使用

是什麼


Spring Cloud Gateway的Filter

生命週期 (2個)

  • Pre 在業務邏輯之前
  • Post 在業務邏輯之後

種類(2個)

  • GatewayFilter 單一 gateway定義的,沒啥用

  • GlobalFilter 全域性 都是用這個

常用的GatewayFilter (gateway定義作用不大)

AddRequestParameter

自定義過濾器(自定義全域性GlobalFilter)

兩個主要介面介紹
  • GlobalFilter
  • Ordered

能幹嘛全域性日誌記錄統一閘道器鑑權
案例程式碼
/**
 * 自定義全域性的filter  Spring Cloud Gateway的Filter 沒啥用,還是自己自定義的好用
 */
@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        log.info("*********come in MyLogGateWayFilter: "+new Date());
        String uname = exchange.getRequest().getQueryParams().getFirst("uname");
        //不成功,就直接返回去
        if(StringUtils.isEmpty(uname)){
            log.info("*****使用者名稱為Null 非法使用者,(┬_┬)");
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);//給人家一個迴應
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

    /**
     * order是過濾器的執行順序,數字越小,執行順序越前
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}
測試

啟動


正確http://localhost:9527/payment/lb?uname=z3