springcloud Gateway網關的路由、斷言、過濾配置

Route(路由)

1、構架pom文件,這裏面需要將web包去掉,因爲Gateway的底層是webflux,而webflux和web是衝突的,只能有一個,需要注意!

<?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>cloud2020</artifactId>
        <groupId>com.king.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>
        <!--eureka-client 客戶端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- 引入自己定義的api通用包,可以使用Payment支付Entity -->
        <dependency>
            <groupId>com.king.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!--<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</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>

2、構建main方法入口,因爲gateway也需要註冊進註冊中心,所以也需要添加註解@EnableEurekaClient

package com.king.springcloud;

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

/**
 * created by king on 2020/4/23 1:19 下午
 */
@SpringBootApplication
@EnableEurekaClient
public class GatewayMain9527 {
    public static void main(String[] args) {
            SpringApplication.run(GatewayMain9527.class,args);
        }
}

3、構建yml文件,此處是簡單的路由配置,等演示成功後,後邊會更改爲動態路由配置

server:
  port: 9527

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

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


eureka:
  client:
    #表示是否將自己註冊進EurekaServer默認爲true。
    register-with-eureka: true
    #是否從EurekaServer抓取已有的註冊信息,默認爲true。單節點無所謂,集羣必須設置爲true才能配合ribbon使用負載均衡
    fetchRegistry: true
    service-url:
      #單機
      defaultZone: http://localhost:7001/eureka
      # 集羣
      #defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,http://eureka7003.com:7003/eureka
  instance:
    instance-id: gateway9527
    prefer-ip-address: true  #訪問路徑可以顯示ip地址
    #Eureka客戶端向服務端發送心跳的時間間隔,單位爲秒(默認30s)
    #lease-renewal-interval-in-seconds: 1
    #Eureka服務端在收到最後一次心跳後等待時間上限,單位爲秒(默認90s,超時將剔除服務
    #lease-expiration-duration-in-seconds: 2

4、此時測試http://localhost:8001/payment/get/1 、http://localhost:8001/payment/lb 和 http://localhost:9527/payment/get/1 、http://localhost:9527/payment/lb得到的結果是一樣是,說明我們的9527gateway已經實現了路由功能

 

而Gateway網關實現路由有兩種方法:

第一種就是yml配置方式,上述就是這一種

第二種就是在代碼中注入RouteLocator的bean,代碼如下:

package com.king.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;

/**
 * created by king on 2020/4/23 2:21 下午
 * 配置了一個id爲myroutebaidu1的路由規則,
 * 當訪問地址http://localhost:9527/guone時會自動轉發到地址: http://news.baidu.com/guonei
 */
@Configuration
public class GatewayConfiguration {
    @Bean
    public RouteLocator customerRouterLocator1(RouteLocatorBuilder builder) {
        RouteLocatorBuilder.Builder routes = builder.routes();
        routes.route("myroutebaidu1", r -> r.path("/guonei").uri("http://news.baidu.com/guonei")).build();
        return routes.build();
    }
    @Bean
    public RouteLocator customerRouterLocator2(RouteLocatorBuilder builder) {
        RouteLocatorBuilder.Builder routes = builder.routes();
        routes.route("myroutebaidu2", r -> r.path("/guoji").uri("http://news.baidu.com/guoji")).build();
        return routes.build();
    }
    //注意:此處的path需要和uri的最後路徑保持一致,不一致會報錯找不到的,這個game就是反例~~
    @Bean
    public RouteLocator customerRouterLocator3(RouteLocatorBuilder builder) {
        RouteLocatorBuilder.Builder routes = builder.routes();
        routes.route("myroutebaidu3", r -> r.path("/mygame").uri("http://news.baidu.com/game")).build();
        return routes.build();
    }
}

可以實現路由到百度新聞的某個標籤模塊

上面是gateway實現路由的簡單配置,默認情況下Gateway會根據註冊中心註冊的服務列表,以註冊中心上微服務名爲路徑創建動態路由進行轉發,從而實現動態路由的功能。下面給出了動態路由創建配置:

1、動態路由配置yml,修改部分:

①是添加了discovery.locator.enabled:true開啓了動態路由功能

②是修改uri爲 lb://開頭 + 註冊中心微服務名 (注意服務名小寫) (lb代表注從註冊中心獲取微服務,有LoadBalance功能)

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

        - id: payment_routh2 #路由的ID,沒有固定規則但要求唯一,建議配合服務名
          uri: lb://cloud-payment-service  #uri以lb://開頭(lb代表從註冊中心獲取服務)
#          uri: http://localhost:8001   #匹配後提供服務的路由地址
          predicates:
            - Path=/payment/lb/**   #斷言,路徑相匹配的進行路由

2、啓動eureka7001、provider8001、provider8002和 gateway9527服務,然後測試訪問http://localhost:9527/payment/get/1,根據響應的結果端口號8001和8002輪訓出現,即可確定實現了動態路由功能。

 

Predicates(斷言)

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

官網例子地址:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/3.0.0.M1/reference/html/#gateway-request-predicates-factories

下面舉例一下 predicates斷言的幾種類型:

  • Loaded RoutePredicateFactory [After]  :時間點之後服務可訪問
  • Loaded RoutePredicateFactory [Before] :時間點之前服務可訪問
  • Loaded RoutePredicateFactory [Between] :兩個之間點之間服務可訪問,datetime2參數必須是後於datetime1
  • Loaded RoutePredicateFactory [Cookie] :請求服務需要帶cookie
    • 此處可使用curl來進行測試 curl http://localhost:9527/payment/lb --Cookie "username=king"
  • Loaded RoutePredicateFactory [Header] :請求服務需要帶header
    • 請求頭要有X-Request-Id屬性並且值爲整數的正則表達式 curl http://localhost:9527/payment/lb -H "X-Request-Id:1234"
  • Loaded RoutePredicateFactory [Host] :請求頭中的header中需要包含host的內容爲somehost.org等這些
    • curl http://localhost:9527/payment/lb -H "host:www.anotherhost.org"  
    • curl http://localhost:9527/payment/lb -H "host:www.somehost.org"
  • Loaded RoutePredicateFactory [Method] :請求爲post請求
    • curl http://localhost:9527/payment/lb -X POST 
  • Loaded RoutePredicateFactory [Path] : 路徑相匹配的進行路由
  • Loaded RoutePredicateFactory [Query] :要有參數名稱並且是正整數才能路由 沒演示成功
  • Loaded RoutePredicateFactory [ReadBodyPredicateFactory] :官網沒看見,不做解釋了
  • Loaded RoutePredicateFactory [RemoteAddr] :需要ip在1-24區間的可以訪問通過,比如 192.168.1.10
  • Loaded RoutePredicateFactory [Weight] :這條路線會將此百分比的流量轉發到這裏,與其他配合服務使用。
  • Loaded RoutePredicateFactory [CloudFoundryRouteService] :官網沒找到,不做解釋了

這裏官網給出的時間點是美國時區的,所以我們需要工具轉換一下爲中國/上海時區

import java.time.ZonedDateTime;

/**
 * created by king on 2020/4/23 3:44 下午
 */
public class T1 {
    public static void main(String[] args) {
        ZonedDateTime zonedDateTime = ZonedDateTime.now();
        System.out.println(zonedDateTime);
        //輸出爲 2020-04-23T15:45:46.581+08:00[Asia/Shanghai]
    }
}

yml的例子我就直接全粘貼了,不再一個個去操作了


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

        - id: payment_routh2 #路由的ID,沒有固定規則但要求唯一,建議配合服務名
          uri: lb://cloud-payment-service  #uri以lb://開頭(lb代表從註冊中心獲取服務)
#          uri: http://localhost:8001   #匹配後提供服務的路由地址
          predicates:
            - Path=/payment/lb/**   #斷言,路徑相匹配的進行路由
#            - After=2020-04-23T15:45:46.581+08:00[Asia/Shanghai]  #此時間點後才能訪問
#            - Before=2020-04-23T18:45:46.581+08:00[Asia/Shanghai]  #此時間點前才能訪問
#            - Between=2020-04-23T15:45:46.581+08:00[Asia/Shanghai],2020-04-24T15:45:46.581+08:00[Asia/Shanghai]  #datetime1和datetime2區間請求可訪問。datetime2參數必須是後於datetime1
#            - Cookie=username,king #請求服務需要帶cookie,此處可使用curl來進行測試 curl http://localhost:9527/payment/lb --Cookie "username=king"
#            - Header=X-Request-Id, \d+ #請求服務需要帶header,請求頭要有X-Request-Id屬性並且值爲整數的正則表達式 curl http://localhost:9527/payment/lb -H "X-Request-Id:1234"
#            - Host=**.somehost.org,**.anotherhost.org #請求頭中的header中需要包含host的內容爲somehost.org等這些 curl http://localhost:9527/payment/lb -H "host:www.anotherhost.org" 或 curl http://localhost:9527/payment/lb -H "host:www.somehost.org"
#            - Method=POST  #請求爲post請求 curl http://localhost:9527/payment/lb  -X POST
#            - Query=username, \d+ #要有參數名稱並且是正整數才能路由  沒演示成功 curl http://localhost:9527/payment/lb?username=1,但是瀏覽器輸入請求這個地址成功測試完成
#            - RemoteAddr=192.168.1.1/24   #需要ip在1-24區間的可以訪問通過,比如 192.168.1.10
#            - Weight=group1, 2 #這條路線會將大約80%的流量轉發到上邊兒,將大約20%的流量轉發到這裏,與其他配合服務使用。

 

Filter(過濾)

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

springcloud gateway的Filter的 :

一般我們是通過實現自定義全局GlobalFilter過濾器,來完成操作的

自定義全局GlobalFilter過濾器搭建演示:

1、新建MyLogGlobalFilter,在類上加註解@Component ,並實現 GlobalFilter, Ordered兩個接口,並自定義攔截規則

  • 先通過exchange獲取參數
  • 驗證參數是否合法
    • 參數不合法:通過exchange的response設置狀態碼,然後響應出去
  • 完成操作後通過 chain.filter(exchange)過濾鏈 傳遞下去
package com.king.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.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Date;

/**
 * created by king on 2020/4/23 5:05 下午
 */
@Component
@Slf4j
public class MyLogGlobalFilter implements GlobalFilter, Ordered {

    /**
     * 1.先通過exchange獲取參數
     * 2.驗證參數是否合法
     *      參數不合法:通過exchange的response設置狀態碼,然後響應出去
     * 3.完成操作後通過 chain.filter(exchange)過濾鏈 傳遞下去
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("*********come in MyLogGlobalFilter: "+new Date());
        String uname = exchange.getRequest().getQueryParams().getFirst("uname");
        if(uname ==null){
            log.info("uname 爲空,非法用戶,請出去~~~~");
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return  response.setComplete();
        }
        return chain.filter(exchange);
    }

    //加載過濾器的順序,一般數字越小,優先級越高
    @Override
    public int getOrder() {
        return 0;
    }
}

2、通過url請求測試Filter是否成功 http://localhost:9527/payment/lb?uname=asga、http://localhost:9527/payment/lb?u=asga

通過uname有值的得到放行,而沒有uname參數的直接返回錯誤~

到此,springcloud 的Gateway 新網關的演示結束了~後續有新的會繼續補充~~~

 

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