1. 程式人生 > 其它 >08 服務閘道器GateWay

08 服務閘道器GateWay

GateWay 閘道器

Cloud 元件全家桶中有一個重要的元件就是閘道器,在1.x 版本都是採用的 Zuul閘道器;

但在 2.x 版本中,zuul 的升級一直跳票,SpringCloud 最後自己研發了一個閘道器替代Zuul.

GateWay 為了提供一種簡單而有效的方式來對 API 進行路由 以及提供一些強大的過濾器功能,例如:熔斷、限流、重試等

選擇 GateWay 的原因


Zuul 1 的模型

三大概念

Route(路由):構建閘道器的基本模組,它由ID,目標URI,一系列的斷言

和過濾器組成,如果斷言為true則匹配該路由

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

Filter(過濾):是SpringCloud框架中的 GateWay的例項,使用過濾器,可以在請求被路由前或者路由之後對請求進行修改


搭建 閘道器9527

  1. 新建模組cloud-gateway-gateway9527
  2. pom

閘道器的pom 檔案不需要 web 和 auactor 依賴

<dependencies>
    <!--gateway-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <!-- 引用自己定義的api通用包,可以使用Payment支付Entity -->
    <dependency>
        <groupId>com.atguigu.springcloud</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>${project.version}</version>
    </dependency>
    <!--eureka client(通過微服務名實現動態路由)-->
    <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>

  1. yml
server:
  port: 9527

spring:
  application:
    name: cloud-gateway

eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    fetch-registry: true
    register-with-eureka: true
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/
  1. 主啟動類
@SpringBootApplication
@EnableEurekaClient
public class GatewayMain9527 {

    public static void main(String[] args) {
        SpringApplication.run(GatewayMain9527.class,args);
    }
}
  1. 修改yml檔案
server:
  port: 9527

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      routes:
        - id: payment_route # 路由的id,沒有規定規則但要求唯一,建議配合服務名
          #匹配後提供服務的路由地址
          uri: http://localhost:8001
          predicates:
            - Path=/payment/get/** # 斷言,路徑相匹配的進行路由

        - id: payment_route2
          uri: http://localhost:8001
          predicates:
            - Path=/payment/lb/** #斷言,路徑相匹配的進行路由

eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    fetch-registry: true
    register-with-eureka: true
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/
  1. 測試 啟動 7001 閘道器9527 8001

通過9527 訪問到 8001

predicate 為 true 訪問成功 false 訪問失敗

配置路由的兩種方式

  1. 在配置檔案yml中配置
  2. 在配置類中配置
    程式碼中注入RouteLocator的Bean

配置類配置

@Configuration
public class GateWayConfig {

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder){
        RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
        routes.route("path_route",
                r -> r.path("/guonei") // 相當於 localhost:9527/guonei  轉到下面的百度
                        .uri("http://news.baidu.com/guonei")).build();


        return routes.build();
    }
}

測試:http://localhost:9527/guonei

動態路由

  1. 修改yml 檔案
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true  #開啟從註冊中心動態建立路由的功能,利用微服務名稱進行路由(預設false)
      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/** #斷言,路徑相匹配的進行路由


測試,啟動7001,8001,8002,9527
http://localhost:9527/payment/lb

常用Predicate的使用

官網:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#gateway-request-predicates-factories

After/Before/Between

先用一個測試類獲取當前時間

import java.time.ZonedDateTime;
public class Test2 {

    public static void main(String[] args) {
        //獲取當前時間串
        ZonedDateTime now = ZonedDateTime.now();//預設時區
        System.out.println(now);
        //2021-12-04T14:32:44.032+08:00[Asia/Shanghai]    }
    }
}
![](https://img2020.cnblogs.com/blog/2316000/202112/2316000-20211204204227454-1201996192.png)


在yml 檔案 中加上

          predicates:
            - Path=/payment/lb/** #斷言,路徑相匹配的進行路由
            # 時間比當前時間晚了一小時
            - After=2021-12-04T15:32:44.032+08:00[Asia/Shanghai]

測試,啟動7001,8001,8002,9527
http://localhost:9527/payment/lb

              #指定時間前才能訪問(Before)
            - Before=2021-12-04T15:32:44.032+08:00[Asia/Shanghai]
              #指定時間內才能訪問(Between)
            - Between=2021-12-04T15:32:44.032+08:00[Asia/Shanghai],2021-12-04T16:32:44.032+08:00[Asia/Shanghai]

需要兩個引數,一個是 Cookie name,一個是正則表示式

路由規則會通過獲取對應的Cookie name 值 和 正則表示式,如果匹配上就會執行路由,如果沒有匹配上則不執行

          predicates:
            - Path=/payment/lb/** #斷言,路徑相匹配的進行路由
            - After=2021-12-04T15:32:44.032+08:00[Asia/Shanghai]
            - Cookie=username,ssyy

Header Route Predicate Factroy

兩個引數 一個是屬性名稱和一個正則表示式,這個屬性值和正則表示式匹配執行

          predicates:
            - Path=/payment/lb/** #斷言,路徑相匹配的進行路由
#            - After=2021-12-04T15:32:44.032+08:00[Asia/Shanghai]
#            - Cookie=username,ssyy
            - Header=X-Request-Id, \d+   #請求頭要有 X-Request-Id屬性並且值為整數的正則表示式


          predicates:
            - Path=/payment/lb/** #斷言,路徑相匹配的進行路由
#            - After=2021-12-04T15:32:44.032+08:00[Asia/Shanghai]
#            - Cookie=username,ssyy
            - Header=X-Request-Id, \d+   #請求頭要有 X-Request-Id屬性並且值為整數的正則表示式
            - Host=**.angenin.com    #Host: xxx.angenin.com 請求是Host必須有**.angenin.com
            - Method=GET	#只允許get請求訪問
            - Path=/payment/lb/**  #訪問的url地址有 /payment/lb/ 才能訪問
            - Query=username, \d+   #url請求地址必須帶上username引數,並且值必須為整數


Filter

路由過濾器可用於修改進入的 HTTP請求和返回的HTTP響應,路由過濾器只能指定路由進行使用

內建了 許多過濾器 都由 GateWayFilter的工廠產生

GatewayFilter(31種)
Global Filter(10種)

自定義過濾器

新建filter.MyLogGateWayFilter

@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 name = exchange.getRequest().getQueryParams().getFirst("name");
        if (name == null){
           log.info("********使用者名稱為null,非法使用者,T T");
           exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
           return exchange.getResponse().setComplete();
        }

        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        //返回值是過濾器的優先順序,越小優先順序越高(最小-2147483648,最大2147483648)
        return 0;
    }
}

啟動7001,8001,8002,9527
http://localhost:9527/payment/lb?name=111

帶著 name 就會成功