SpringCloud——中級(二)服務網關Gateway

Gateway新一代網關

一、概述簡介

1、官網

上一代zuul 1.X官網
當前的gateway

2、是什麼

gateway是原zuul1.x版的替代版
Gateway旨在提供一種簡單而有效的方式來對API進行路由,以及提供一些強大的過濾器功能,例如:熔斷、限流、重試等。
在這裏插入圖片描述
SpringCloud Gateway使用的Webflux中的reactor-netty響應式編程組件,底層使用了Netty通訊框架

3、能幹嘛

反向代理、鑑權、流量控制、熔斷、日誌監控

4、微服務架構中網關在哪裏

在這裏插入圖片描述

5、有Zuul了怎麼又出來了gateway

Gateway具有以下特性:
基於Spring Framework 5,Project Reactor 和Spring Boot 2.0進行構建
動態路由:能夠匹配任何請求屬性;
可以對路由指定Predicate(斷言)和Filter(過濾器);
集成Hystrix 的斷路器功能;
集成Spring Cloud 服務發現功能;
易於編寫的Predicate(斷言)和Filter(過濾器);
請求限流功能;
支持路徑重寫;
在這裏插入圖片描述
Gateway底層使用WebFlux+Netty 非阻塞異步的框架

二、三大核心概念

1、Route(路由)

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

2、Predicate(斷言)

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

3、Filter(過濾)

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

4、總體

匹配方式就叫斷言,實現這個匹配方式就叫filter,對外表現出來就是路由的功能。
在這裏插入圖片描述
web請求,通過一些匹配條件,定位到真正的服務節點。並在這個轉發過程的前後,進行一些精細化控制predicate就是我們的匹配條件;
而 filter,就可以理解爲個無所不能的攔截器。有了這兩個元素,再加上目標u。就可以實現一個具體的路由了

三、Gateway工作流程

1、官網總結

在這裏插入圖片描述
客戶端向 Spring Cloud Gateway發出請求。然後在 Gateway Handler Mapping中找到與請求相匹配的路由,將其發送到 GatewayWeb Handler。

Handler再通過指定的過濾器鏈來將請求發送到我們實際的服務執行業務邏輯,然後返回
過濾器之間用虛線分開是因爲過濾器可能會在發送代理請求之前("pre”)或之後("post”)執行業務邏輯。

Filter在"pre"類型的過濾器可以做參數校驗、權限校驗、流量監控、日誌輸出、協議轉換等,
在"post”類型的過濾器中可以做響應內容、響應頭的修改,日誌的輸出,流量監控等有着非常重要的作用。

2、核心邏輯

路由轉發+執行過濾器鏈

四、入門配置

1、新建Model

cloud-gateway-gateway9527

2、pom

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

3、yml

server:
  port: 9527
spring:
  application:
    name: cloud-gateway

eureka:
  instance:
    hostname: cloud-gateway-serrvice
  client:     #服務提供者provider註冊進eureka服務列表內
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka

4、業務類

無。。。

5、主啓動類

package com.atguigu.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

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

6、9527網關如何做路由映射

1)cloud-provider-payment8001看看controller的訪問地址

get、lb

2)我們目前不想 暴露8001端口,希望在8001外面套一層8527

7、YML新增網關配置

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

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

eureka:
  instance:
    hostname: cloud-gateway-serrvice
  client:     #服務提供者provider註冊進eureka服務列表內
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka

8、測試

1)啓動7001

2)啓動8001

3)啓動9527網關

4)訪問說明

http://localhost:8001/payment/lb

http://localhost:9527/payment/lb

9、YML配置說明

Gateway網關路由有兩種配置方式:
1、yml文件中配置,見上。。
2、代碼中注入RouteLocator的Bean(硬編碼)
自己寫一個:通過9527網關訪問到外網的百度新聞網址
http://news.baidu.com/guonei
配置代碼如下:

package com.atguigu.springcloud.config;

import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class GatewayConfig {
    /*
    * 配置了一個id爲route_name的路由規則
    * 當訪問地址:localhost:9527/guonei時會自動轉發到地址:http://news.baidu.com/guonei
    * */
    @Bean
    public RouteLocator customrouts(RouteLocatorBuilder routeLocatorBuilder){

        RouteLocatorBuilder.Builder routes=routeLocatorBuilder.routes();

        routes.route("path_route_atguigu", r -> r.path("/guonei").uri("http://news.baidu.com/guonei")).build();

        return routes.build();
    }
}

測試:http://localhost:9527/guonei
可以成功訪問

五、通過微服務名實現動態路由

1、實現方式

默認情況下 Gateway會根據註冊中心註冊的服務列表,
以註冊中心上微服務名爲路徑創建動態路由進行轉發,從而實現動態路由的功能

2、啓動:7001、8001/8002

3、pom

4、YML

注意:
uri協議爲lb,表示啓用Gateway的負載均衡功能。
Ib: //servicename spring cloudgateway在微服務中自動爲我們創建的負載均衡uri

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

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

eureka:
  instance:
    hostname: cloud-gateway-serrvice
  client:     #服務提供者provider註冊進eureka服務列表內
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka

5、測試

http://localhost:9527/payment/lb
8001和8002兩個端口切換

六、Predicate的使用

1、是什麼

2、Route Predicate Factories這個是什麼

詳見官網:官網
在這裏插入圖片描述

3、常用的Route Predicate

在這裏插入圖片描述

1)關於時間的

After Route Predicate
Before Route Predicate
Between Route Predicate

        - id: payment_routh2 #payment_route   #路由的ID,沒有固定規則但要求唯一,建議配合服務名
         # uri: http://localhost:8001  #匹配後提供服務的路由地址
          uri: lb://cloud-payment-service #匹配後提供服務的路由地址
          predicates:
            - Path=/payment/lb/**   #斷言,路徑相匹配的進行路由
            - After=2020-04-06T14:29:45.412+08:00[Asia/Shanghai]
            - Before=2020-04-06T14:29:45.412+08:00[Asia/Shanghai]

2)Cookie Route Predicate

Cookie route predicate需要兩個參數,一個是 Cookie name,個是正則表達式。
路由規則會通過獲取對應的 Cookie name值和正則表達式去匹配,如果匹配上就會執行路由,如果沒有匹配上則不執行

        - id: payment_routh2 #payment_route   #路由的ID,沒有固定規則但要求唯一,建議配合服務名
         # uri: http://localhost:8001  #匹配後提供服務的路由地址
          uri: lb://cloud-payment-service #匹配後提供服務的路由地址
          predicates:
            - Path=/payment/lb/**   #斷言,路徑相匹配的進行路由
            - After=2020-04-06T14:29:45.412+08:00[Asia/Shanghai]
            - Before=2020-04-06T14:29:45.412+08:00[Asia/Shanghai]
            - Cookie=username,zzyy

使用curl測試:
不帶cookie訪問:

curl http://localhost:9527/payment/lb

帶cookie訪問:

curl http://localhost:9527/payment/lb --cookie "username=zzyy"

在這裏插入圖片描述

3)Header

yml文件中:

- Header=X-Request-Id,/d+ #請求頭要有X-Request-Id屬性並且值爲整數的正則表達式
curl http://localhost:9527/payment/lb -H "X-Request-id:123

在這裏插入圖片描述

4)Method

yml文件中:

- Method=GET

5)小總結

ALL
說白了,Predicate就是爲了實現一組匹配規則,讓請求過來找到對應的Route進行處理

七、Filter的使用

1、是什麼

路由過濾器可用於修改進入的HTTP請求和返回的HTTP響應,路由過濾器只能指定路由進行使用。
Spring Cloud Gateway內置了多種路由過濾器,他們都由 Gateway Filter的工廠類來產生

2、Spring Cloud Gateway的Filtere

1)生命週期,Only Two

pre、post

2)種類,Only Two

1.GatewayFilter:官網描述

2.GlobalFilter

3、常用的GatetwayFilter

AddRequestParameter:

          filters:
            - AddRequestParameter=X-Request-Id,1024 #過濾器工廠會在匹配的頭加上一對清求頭,客稱爲X-Request-Id值爲024

4、自定義過濾器

自定義全局GlobalFilter:

1)兩個主要接口介紹

implements GlobalFilter,Ordered

2)能幹嘛

全局日誌記錄
統一網關鑑權

3)案例代碼

package com.atguigu.springcloud.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
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 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(uname==null){
            log.info("****用戶名爲空null,非法用戶!!");
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

4)測試

啓動:7001、8001、8002、9527
地址:localhost:9527/payment/lb?uname=z3
localhost:9527/payment/lb

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章