熬夜肝了這篇Spring Cloud Gateway的功能及綜合使用

前言

SpringCloud 是微服務中的翹楚,最佳的落地方案。

Spring Cloud Gateway 是 Spring Cloud 新推出的網關框架,之前是 Netflix Zuul。網關通常在項目中為了簡化

前端的調用邏輯,同時也簡化內部服務之間互相調用的複雜度;具體作用就是轉發服務,接收並轉發所有內外

部的客戶端調用;其他常見的功能還有許可權認證,限流控制等等。

本部落格會提到網關的基本轉發功能熔斷功能限流功能以及功能的綜合使用

源碼

GitHub地址://github.com/intomylife/SpringCloud

環境

JDK 1.8.0 +

Maven 3.0 +

SpringBoot 2.0.3

SpringCloud Finchley.RELEASE

Redis 3.0 +

開發工具

IntelliJ IDEA

正文

commons 工程

commons 工程 – POM 文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="//maven.apache.org/POM/4.0.0" xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="//maven.apache.org/POM/4.0.0 //maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
 
    <!-- 三坐標 -->
    <groupId>com.zwc</groupId>
    <artifactId>springcloud-gateway-commons</artifactId>
    <version>1.0</version>
 
    <!-- 工程名稱和描述 -->
    <name>springcloud-gateway-commons</name>
    <description>公用工程</description>
 
    <!-- 打包方式 -->
    <packaging>jar</packaging>
 
    <!-- 在 properties 下聲明相應的版本資訊,然後在 dependency 下引用的時候用 ${} 就可以引入該版本 jar 包了 -->
    <properties>
        <!-- 編碼 -->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <!-- jdk -->
        <java.version>1.8</java.version>
 
        <!-- SpringBoot -->
        <platform-bom.version>Cairo-SR3</platform-bom.version>
 
        <!-- SpringCloud -->
        <spring-cloud-dependencies.version>Finchley.RELEASE</spring-cloud-dependencies.version>
    </properties>
 
    <!-- 加入依賴 -->
    <dependencies>
 
    </dependencies>
 
    <!-- 依賴 jar 包版本管理的管理器 -->
    <!-- 如果 dependencies 里的 dependency 自己沒有聲明 version 元素,那麼 maven 就此處來找版本聲明。 -->
    <!-- 如果有,就會繼承它;如果沒有就會報錯,告訴你沒有版本資訊 -->
    <!-- 優先順序:如果 dependencies 里的 dependency 已經聲明了版本資訊,就不會生效此處的版本資訊了 -->
    <dependencyManagement>
        <dependencies>
            <!-- SpringBoot -->
            <dependency>
                <groupId>io.spring.platform</groupId>
                <artifactId>platform-bom</artifactId>
                <version>${platform-bom.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- SpringCloud -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud-dependencies.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
 
    <!-- 插件依賴 -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
 
</project>

配置一些共用依賴

commons 工程 – 項目結構

service 工程

**① 此工程下有四個模組:一個註冊中心,一個網關以及兩個提供者

② 兩個提供者除埠不一致以外,其他程式碼基本一致

registry-service(註冊中心)

registry-service – POM 文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="//maven.apache.org/POM/4.0.0" xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="//maven.apache.org/POM/4.0.0 //maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
 
    <!-- 繼承父 -->
    <parent>
        <groupId>com.zwc</groupId>
        <artifactId>springcloud-gateway-service</artifactId>
        <version>1.0</version>
    </parent>
 
    <!-- 三坐標 -->
    <groupId>com.zwc</groupId>
    <artifactId>springcloud-gateway-registry-service</artifactId>
    <version>1.0</version>
 
    <!-- 工程名稱描述 -->
    <name>springcloud-gateway-registry-service</name>
    <description>註冊中心</description>
 
    <!-- 打包方式 -->
    <packaging>jar</packaging>
 
    <!-- 在 properties下聲明相應的版本資訊,然後在dependency下引用的時候用 ${} 就可以引入該版本jar包了 -->
    <properties>
 
    </properties>
 
    <!-- 加入依賴 -->
    <dependencies>
        <!-- 服務註冊中心 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>
 
    <!-- 插件依賴 -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
 
</project>

主要加入 spring-cloud-starter-netflix-eureka-server 依賴

registry-service – application.yml 配置文件

#埠
server:
  port: 8761
 
#應用名稱
spring:
  application:
    name: eureka-server
 
eureka:
  instance:
    # 使用 ip 代替實例名
    prefer-ip-address: true
    # 實例的主機名
    hostname: ${spring.cloud.client.ip-address}
    # 實例的 ID 規則
    instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
  client:
    # 是否向註冊中心註冊自己
    registerWithEureka: false
    # 是否向註冊中心獲取註冊資訊
    fetchRegistry: false
    serviceUrl:
      # 註冊中心地址
      defaultZone: //${eureka.instance.hostname}:${server.port}/eureka/

這裡使用了默認的 8761 埠,當然也可以更改,不過在發現調用服務端的註冊中心地址埠要與它一致

registry-service – 啟動類

package com.zwc;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
 
@SpringBootApplication
@EnableEurekaServer
public class SpringcloudGatewayRegistryServiceApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(SpringcloudGatewayRegistryServiceApplication.class, args);
    }
 
}

在啟動類中添加 @EnableEurekaServer 註解表示此工程是註冊中心

registry-service – 啟動項目

  1. 項目啟動成功後訪問 //localhost:8761/ 即可看到 eureka-server 主頁面

註:由於服務工程 A 和服務工程 B 除埠不一致以外,其他程式碼基本一致,所以服務工程 B 不再贅述

a-service(服務工程 A)

a-service – POM 文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="//maven.apache.org/POM/4.0.0" xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="//maven.apache.org/POM/4.0.0 //maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
 
    <!-- 繼承父 -->
    <parent>
        <groupId>com.zwc</groupId>
        <artifactId>springcloud-gateway-a-service</artifactId>
        <version>1.0</version>
    </parent>
 
    <!-- 三坐標 -->
    <groupId>com.zwc</groupId>
    <artifactId>springcloud-gateway-a-service-core</artifactId>
    <version>1.0</version>
 
    <!-- 工程名稱描述 -->
    <name>springcloud-gateway-a-service-core</name>
    <description>服務工程 - A 核心</description>
 
    <!-- 打包方式 -->
    <packaging>jar</packaging>
 
    <!-- 在 properties下聲明相應的版本資訊,然後在dependency下引用的時候用 ${} 就可以引入該版本jar包了 -->
    <properties>
 
    </properties>
 
    <!-- 加入依賴 -->
    <dependencies>
        <!-- commons工程 依賴 -->
        <dependency>
            <groupId>com.zwc</groupId>
            <artifactId>springcloud-gateway-commons</artifactId>
            <version>1.0</version>
        </dependency>
 
        <!-- api工程 依賴 -->
        <dependency>
            <groupId>com.zwc</groupId>
            <artifactId>springcloud-gateway-a-service-api</artifactId>
            <version>1.0</version>
        </dependency>
 
        <!-- springboot web 依賴 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
 
        <!-- 提供者消費者 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>
 
    <!-- 插件依賴 -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
 
</project>

加入spring-cloud-starter-netflix-eureka-client依賴

a-service – application.yml 配置文件

#埠
server:
  port: 9000
 
#應用名稱
spring:
  application:
    name: gateway-service
 
eureka:
  instance:
    # 使用 ip 代替實例名
    prefer-ip-address: true
    # 實例的主機名
    hostname: ${spring.cloud.client.ip-address}
    # 實例的 ID 規則
    instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
  client:
    serviceUrl:
      # 註冊中心地址
      defaultZone: //${eureka.instance.hostname}:8761/eureka/

注意此處配置註冊中心地址的埠為 8761 也就是上面註冊中心工程配置的埠

a-service – controller 前端控制器(提供服務)

package com.zwc.a.controller;
 
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
/*
 * @ClassName ASayHelloController
 * @Desc TODO   Say Hello
 * @Date 2019/5/20 23:24
 * @Version 1.0
 */
@RestController
public class ASayHelloController {
 
    /*
     * @ClassName ASayHelloController
     * @Desc TODO   讀取配置文件中的埠
     * @Date 2019/5/20 23:24
     * @Version 1.0
     */
    @Value("${server.port}")
    private String port;
 
    /*
     * @ClassName ASayHelloController
     * @Desc TODO   Say Hello
     * @Date 2019/5/20 23:24
     * @Version 1.0
     */
    @RequestMapping("/hello")
    public String hello(){
        return "Hello!I'm a. port:" + port;
    }
 
    /*
     * @ClassName ASayHelloController
     * @Desc TODO   接收從網關傳入的參數
     * @Date 2019/6/23 16:28
     * @Version 1.0
     */
    @RequestMapping("/name")
    public String name(String name){
        return "My name is " + name + ". aaa";
    }
 
    /*
     * @ClassName ASayHelloController
     * @Desc TODO   接收從網關傳入的參數
     * @Date 2019/6/23 16:52
     * @Version 1.0
     */
    @RequestMapping("/age")
    public String age(String age){
        return "I am " + age + " years old this year. aaa";
    }
 
    /*
     * @ClassName ASayHelloController
     * @Desc TODO   接收從網關傳入的參數
     * @Date 2019/6/29 22:00
     * @Version 1.0
     */
    @RequestMapping("/routeAll")
    public String routeAll(String pass) {
        return "Can I pass? " + pass + "! port:" + port;
    }
 
}

提供輸出字元串服務,供網關調用

a-service – 啟動類

package com.zwc;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
 
@SpringBootApplication
@EnableEurekaClient
public class SpringcloudGatewayAServiceCoreApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(SpringcloudGatewayAServiceCoreApplication.class, args);
    }
 
}

添加 @EnableEurekaClient 註解表示此工程可以向註冊中心提供服務

a-service – 啟動項目

  1. 刷新 //localhost:8761/(註冊中心)可以看到服務已經被註冊進來了


2. 項目啟動成功後訪問://localhost:9000/hello

  1. 輸出內容:’Hello!I’m a. port:9000′

  2. 同樣啟動服務工程 B後,刷新 //localhost:8761/(註冊中心)

  1. 項目啟動成功後訪問://localhost:9001/hello

  2. 輸出內容:’Hello!I’m b. port:9001′

  3. 其他介面是下面網關服務啟動後轉發調用的,也是本部落格的重頭戲

master-service(網關)

master-service – POM 文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="//maven.apache.org/POM/4.0.0" xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="//maven.apache.org/POM/4.0.0 //maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
 
    <!-- 繼承父 -->
    <parent>
        <groupId>com.zwc</groupId>
        <artifactId>springcloud-gateway-service</artifactId>
        <version>1.0</version>
    </parent>
 
    <!-- 三坐標 -->
    <groupId>com.zwc</groupId>
    <artifactId>springcloud-gateway-master-service</artifactId>
    <version>1.0</version>
 
    <!-- 工程名稱描述 -->
    <name>springcloud-gateway-master-service</name>
    <description>Spring Cloud Gateway 服務網關</description>
 
    <!-- 打包方式 -->
    <packaging>jar</packaging>
 
    <!-- 在 properties下聲明相應的版本資訊,然後在 dependency 下引用的時候用 ${} 就可以引入該版本 jar 包了 -->
    <properties>
        <!-- ali json -->
        <fastjson.version>1.2.47</fastjson.version>
    </properties>
 
    <!-- 加入依賴 -->
    <dependencies>
        <!-- 提供者消費者 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
 
        <!-- gateway -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
 
        <!-- redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
        </dependency>
 
        <!-- hystrix -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
 
        <!-- ali json依賴 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>${fastjson.version}</version>
        </dependency>
    </dependencies>
 
    <!-- 插件依賴 -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
 
</project>

加入spring-cloud-starter-netflix-eureka-client 依賴:提供和註冊服務

加入spring-cloud-starter-gateway 依賴:gateway

加入spring-boot-starter-data-redis-reactive 依賴:結合 Redis 限流

加入spring-cloud-starter-netflix-hystrix 依賴:熔斷器

master-service – application.yml 配置文件

#埠
server:
  port: 8000
 
spring:
  profiles:
    # 指定配置
    # route_simple:簡單嘗試
    # route_stripPrefix:截取請求
    # route_uri:轉髮指定地址並傳入參數
    # route_addRequestParameter:轉髮指定服務並傳入參數
    # route_hystrix:熔斷
    # route_requestRateLimiter:限流
    # route_all:綜合
    active: route_simple
 
---
 
spring:
  # 配置文件名稱,用來標識不同環境的配置。由 spring.profiles.active 的值來決定使用哪組配置。
  ## 簡單嘗試
  profiles: route_simple
  application:
    # 應用名稱
    name: gateway-master
  cloud:
    gateway:
      discovery:
        locator:
          # 是否和服務註冊與發現組件結合,設置為 true 後可以直接使用應用名稱調用服務
          enabled: true
      # 路由(routes:路由,它由唯一標識(ID)、目標服務地址(uri)、一組斷言(predicates)和一組過濾器組成(filters)。filters 不是必需參數。)
      routes:
      # 路由標識(id:標識,具有唯一性)   簡單嘗試
      - id: route_simple
        # 目標服務地址(uri:地址,請求轉發後的地址)
        uri: //www.zouwencong.com
        # 路由條件(predicates:斷言,匹配 HTTP 請求內容)
        predicates:
        ## 轉發地址格式為 uri/archive
        - Path=/archive
 
eureka:
  instance:
    # 使用 ip 代替實例名
    prefer-ip-address: true
    # 實例的主機名
    hostname: ${spring.cloud.client.ip-address}
    # 實例的 ID 規則
    instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
  client:
    serviceUrl:
      # 註冊中心地址
      defaultZone: //${eureka.instance.hostname}:8761/eureka/
 
logging:
  level:
    # log 級別
    org.springframework.cloud.gateway: debug
 
---
 
spring:
  # 配置文件名稱,用來標識不同環境的配置。由 spring.profiles.active 的值來決定使用哪組配置。
  ## 截取請求
  profiles: route_stripPrefix
  application:
    # 應用名稱
    name: gateway-master
  cloud:
    gateway:
      discovery:
        locator:
          # 是否和服務註冊與發現組件結合,設置為 true 後可以直接使用應用名稱調用服務
          enabled: true
      # 路由(routes:路由,它由唯一標識(ID)、目標服務地址(uri)、一組斷言(predicates)和一組過濾器組成(filters)。filters 不是必需參數。)
      routes:
      # 路由標識(id:標識,具有唯一性)   截取請求
      - id: route_simple
        # 目標服務地址(uri:地址,請求轉發後的地址)
        uri: //www.zouwencong.com
        # 路由條件(predicates:斷言,匹配 HTTP 請求內容)
        predicates:
        ## 轉發地址格式為 uri/archive,/str 部分會被下面的過濾器給截取掉
        - Path=/str/archive
        filters:
        ## 截取路徑位數
        - StripPrefix=1
 
eureka:
  instance:
    # 使用 ip 代替實例名
    prefer-ip-address: true
    # 實例的主機名
    hostname: ${spring.cloud.client.ip-address}
    # 實例的 ID 規則
    instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
  client:
    serviceUrl:
      # 註冊中心地址
      defaultZone: //${eureka.instance.hostname}:8761/eureka/
 
logging:
  level:
    # log 級別
    org.springframework.cloud.gateway: debug
 
---
 
spring:
  # 配置文件名稱,用來標識不同環境的配置。由 spring.profiles.active 的值來決定使用哪組配置。
  ## 轉髮指定地址並傳入參數
  profiles: route_uri
  application:
    # 應用名稱
    name: gateway-master
  cloud:
    gateway:
      discovery:
        locator:
          # 是否和服務註冊與發現組件結合,設置為 true 後可以直接使用應用名稱調用服務
          enabled: true
      # 路由(routes:路由,它由唯一標識(ID)、目標服務地址(uri)、一組斷言(predicates)和一組過濾器組成(filters)。filters 不是必需參數。)
      routes:
      # 路由標識(id:標識,具有唯一性)   轉髮指定地址並傳入參數
      - id: route_uri
        # 目標服務地址(uri:地址,請求轉發後的地址)
        uri: //localhost:9000
        # 路由條件(predicates:斷言,匹配 HTTP 請求內容)
        predicates:
        ## 匹配 GET 請求
        - Method=GET
        # 過濾器(filters:過濾器,過濾規則)
        filters:
        ## 添加指定參數
        - AddRequestParameter=name, zwc
 
eureka:
  instance:
    # 使用 ip 代替實例名
    prefer-ip-address: true
    # 實例的主機名
    hostname: ${spring.cloud.client.ip-address}
    # 實例的 ID 規則
    instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
  client:
    serviceUrl:
      # 註冊中心地址
      defaultZone: //${eureka.instance.hostname}:8761/eureka/
 
logging:
  level:
    # log 級別
    org.springframework.cloud.gateway: debug
 
---
 
spring:
  # 配置文件名稱,用來標識不同環境的配置。由 spring.profiles.active 的值來決定使用哪組配置。
  ## 轉髮指定服務並傳入參數
  profiles: route_addRequestParameter
  application:
    # 應用名稱
    name: gateway-master
  cloud:
    gateway:
      discovery:
        locator:
          # 是否和服務註冊與發現組件結合,設置為 true 後可以直接使用應用名稱調用服務
          enabled: true
      # 路由(routes:路由,它由唯一標識(ID)、目標服務地址(uri)、一組斷言(predicates)和一組過濾器組成(filters)。filters 不是必需參數。)
      routes:
      # 路由標識(id:標識,具有唯一性)   轉髮指定服務並傳入參數
      - id: route_addRequestParameter
        # 目標服務地址(uri:地址,請求轉發後的地址)
        uri: lb://gateway-service
        # 路由條件(predicates:斷言,匹配 HTTP 請求內容)
        predicates:
        ## 匹配 GET 請求
        - Method=GET
        # 過濾器(filters:過濾器,過濾規則)
        filters:
        ## 添加指定參數
        - AddRequestParameter=age, three
 
eureka:
  instance:
    # 使用 ip 代替實例名
    prefer-ip-address: true
    # 實例的主機名
    hostname: ${spring.cloud.client.ip-address}
    # 實例的 ID 規則
    instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
  client:
    serviceUrl:
      # 註冊中心地址
      defaultZone: //${eureka.instance.hostname}:8761/eureka/
 
logging:
  level:
    # log 級別
    org.springframework.cloud.gateway: debug
 
---
 
spring:
  # 配置文件名稱,用來標識不同環境的配置。由 spring.profiles.active 的值來決定使用哪組配置。
  ## 熔斷
  profiles: route_hystrix
  application:
    # 應用名稱
    name: gateway-master
  cloud:
    gateway:
      discovery:
        locator:
          # 是否和服務註冊與發現組件結合,設置為 true 後可以直接使用應用名稱調用服務
          enabled: true
      # 路由(routes:路由,它由唯一標識(ID)、目標服務地址(uri)、一組斷言(predicates)和一組過濾器組成(filters)。filters 不是必需參數。)
      routes:
      # 路由標識(id:標識,具有唯一性)   熔斷
      - id: route_hystrix
        # 目標服務地址(uri:地址,請求轉發後的地址)
        uri: lb://gateway-service
        # 路由條件(predicates:斷言,匹配 HTTP 請求內容)
        predicates:
        ## 匹配 GET 請求
        - Method=GET
        # 過濾器(filters:過濾器,過濾規則)
        filters:
        ## 添加指定參數
        - AddRequestParameter=age, three
        ## 熔斷
        - name: Hystrix
          args:
            name: fallbackcmd
            ### fallback 時調用的方法 //localhost:8000/fallback
            fallbackUri: forward:/fallback
 
eureka:
  instance:
    # 使用 ip 代替實例名
    prefer-ip-address: true
    # 實例的主機名
    hostname: ${spring.cloud.client.ip-address}
    # 實例的 ID 規則
    instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
  client:
    serviceUrl:
      # 註冊中心地址
      defaultZone: //${eureka.instance.hostname}:8761/eureka/
 
logging:
  level:
    # log 級別
    org.springframework.cloud.gateway: debug
 
---
 
spring:
  # 配置文件名稱,用來標識不同環境的配置。由 spring.profiles.active 的值來決定使用哪組配置。
  ## 限流
  profiles: route_requestRateLimiter
  redis:
    host: localhost
    port: 6379
    database: 0
  application:
    # 應用名稱
    name: gateway-master
  cloud:
    gateway:
      discovery:
        locator:
          # 是否和服務註冊與發現組件結合,設置為 true 後可以直接使用應用名稱調用服務
          enabled: true
      # 路由(routes:路由,它由唯一標識(ID)、目標服務地址(uri)、一組斷言(predicates)和一組過濾器組成(filters)。filters 不是必需參數。)
      routes:
      # 路由標識(id:標識,具有唯一性)   限流
      - id: route_requestRateLimiter
        # 目標服務地址(uri:地址,請求轉發後的地址)
        uri: lb://gateway-service
        # 路由條件(predicates:斷言,匹配 HTTP 請求內容)
        predicates:
        ## 匹配 GET 請求
        - Method=GET
        # 過濾器(filters:過濾器,過濾規則)
        filters:
        ## 添加指定參數
        - AddRequestParameter=age, three
        ## 限流
        - name: RequestRateLimiter
          args:
            ### 限流過濾器的 Bean 名稱
            key-resolver: '#{@uriKeyResolver}'
            ### 希望允許用戶每秒處理多少個請求
            redis-rate-limiter.replenishRate: 1
            ### 用戶允許在一秒鐘內完成的最大請求數
            redis-rate-limiter.burstCapacity: 3
 
eureka:
  instance:
    # 使用 ip 代替實例名
    prefer-ip-address: true
    # 實例的主機名
    hostname: ${spring.cloud.client.ip-address}
    # 實例的 ID 規則
    instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
  client:
    serviceUrl:
      # 註冊中心地址
      defaultZone: //${eureka.instance.hostname}:8761/eureka/
 
logging:
  level:
    # log 級別
    org.springframework.cloud.gateway: debug
 
---
 
spring:
  # 配置文件名稱,用來標識不同環境的配置。由 spring.profiles.active 的值來決定使用哪組配置。
  ## 綜合
  profiles: route_all
  redis:
    host: localhost
    port: 6379
    database: 0
  application:
    # 應用名稱
    name: gateway-master
  cloud:
    gateway:
      discovery:
        locator:
          # 是否和服務註冊與發現組件結合,設置為 true 後可以直接使用應用名稱調用服務
          enabled: true
      # 路由(routes:路由,它由唯一標識(ID)、目標服務地址(uri)、一組斷言(predicates)和一組過濾器組成(filters)。filters 不是必需參數。)
      routes:
      # 路由標識(id:標識,具有唯一性)   綜合
      - id: route_all
        # 目標服務地址(uri:地址,請求轉發後的地址)
        uri: lb://gateway-service
        # 路由條件(predicates:斷言,匹配 HTTP 請求內容)
        predicates:
        ## 轉發地址格式為 uri/routeAll,/all 部分會被下面的過濾器給截取掉
        - Path=/all/routeAll
        ## 匹配 GET 請求
        - Method=GET
        # 過濾器(filters:過濾器,過濾規則)
        filters:
        ## 截取路徑位數
        - StripPrefix=1
        ## 添加指定參數
        - AddRequestParameter=pass, yes
        ## 熔斷
        - name: Hystrix
          args:
            name: fallbackcmd
            ### fallback 時調用的方法 //localhost:8000/fallback
            fallbackUri: forward:/fallback
        ## 限流
        - name: RequestRateLimiter
          args:
            ### 限流過濾器的 Bean 名稱
            key-resolver: '#{@uriKeyResolver}'
            ### 希望允許用戶每秒處理多少個請求
            redis-rate-limiter.replenishRate: 1
            ### 用戶允許在一秒鐘內完成的最大請求數
            redis-rate-limiter.burstCapacity: 3
 
eureka:
  instance:
    # 使用 ip 代替實例名
    prefer-ip-address: true
    # 實例的主機名
    hostname: ${spring.cloud.client.ip-address}
    # 實例的 ID 規則
    instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
  client:
    serviceUrl:
      # 註冊中心地址
      defaultZone: //${eureka.instance.hostname}:8761/eureka/
 
logging:
  level:
    # log 級別
    org.springframework.cloud.gateway: debug

注意配置註冊中心地址的埠都為 8761 也就是上面註冊中心工程配置的埠

每一對 ‘—‘ 符號中的配置文件都是單獨的,使用 spring.profiles.active 指定

每一對 ‘—‘ 符號中的配置文件都只配置了一個 route(路由)

route(路由)由四部分組成,其中 filters 不是必須參數

唯一標識(ID)、目標服務地址(uri)、一組斷言(predicates)和一組過濾器組成(filters)

master-service – 簡單嘗試

spring:
  # 配置文件名稱,用來標識不同環境的配置。由 spring.profiles.active 的值來決定使用哪組配置。
  ## 簡單嘗試
  profiles: route_simple
  application:
    # 應用名稱
    name: gateway-master
  cloud:
    gateway:
      discovery:
        locator:
          # 是否和服務註冊與發現組件結合,設置為 true 後可以直接使用應用名稱調用服務
          enabled: true
      # 路由(routes:路由,它由唯一標識(ID)、目標服務地址(uri)、一組斷言(predicates)和一組過濾器組成(filters)。filters 不是必需參數。)
      routes:
      # 路由標識(id:標識,具有唯一性)   簡單嘗試
      - id: route_simple
        # 目標服務地址(uri:地址,請求轉發後的地址)
        uri: //www.zouwencong.com
        # 路由條件(predicates:斷言,匹配 HTTP 請求內容)
        predicates:
        ## 轉發地址格式為 uri/archive
        - Path=/archive
  1. 停止註冊中心工程(registry-service)、服務工程 A 和服務工程 B

  2. 把 master-service – application.yml 配置文件中最上面的 spring.profiles.active 的值更改為 route_simple

  3. 上面配置文件內容意思是當訪問 //localhost:8000/archive (網關地址/archive)

    會被轉發到 //www.zouwencong.com/archive/ (uri/archive)

  4. 啟動註冊中心工程(registry-service)和網關工程(master-service)

  5. 項目啟動成功後訪問://localhost:8000/archive

  6. 發現頁面會自動被跳轉到://www.zouwencong.com/archive/

  7. 證明服務轉發成功

master-service – 截取請求

spring:
  #配置文件名稱,用來標識不同環境的配置。由 spring.profiles.active 的值來決定使用哪組配置。
  ##截取請求
  profiles: route_stripPrefix
  application:
    # 應用名稱
    name: gateway-master
  cloud:
    gateway:
      discovery:
        locator:
          # 是否和服務註冊與發現組件結合,設置為 true 後可以直接使用應用名稱調用服務
          enabled: true
      # 路由(routes:路由,它由唯一標識(ID)、目標服務地址(uri)、一組斷言(predicates)和一組過濾器組成(filters)。filters 不是必需參數。)
      routes:
      # 路由標識(id:標識,具有唯一性)   截取請求
      - id: route_simple
        # 目標服務地址(uri:地址,請求轉發後的地址)
        uri: //www.zouwencong.com
        # 路由條件(predicates:斷言,匹配 HTTP 請求內容)
        predicates:
        ## 轉發地址格式為 uri/archive,/str 部分會被下面的過濾器給截取掉
        - Path=/str/archive
        filters:
        ## 截取路徑位數
        - StripPrefix=1
 
eureka:
  instance:
    # 使用 ip 代替實例名
    prefer-ip-address: true
    # 實例的主機名
    hostname: ${spring.cloud.client.ip-address}
    # 實例的 ID 規則
    instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
  client:
    serviceUrl:
      # 註冊中心地址
      defaultZone: //${eureka.instance.hostname}:8761/eureka/
 
logging:
  level:
    # log 級別
    org.springframework.cloud.gateway: debug
  1. 停止註冊中心工程(registry-service)和網關工程(master-service)

  2. 把 master-service – application.yml 配置文件中最上面的 spring.profiles.active 的值更改為 route_stripPrefix

  3. 上面配置文件內容意思是訪問的路徑 //localhost:8000/str/archive (網關地址/str/archive)截取 /str 部分,

    截取後被轉發到 //www.zouwencong.com/archive/ (uri/archive)

  4. 啟動註冊中心工程(registry-service)和網關工程(master-service)

  5. 項目啟動成功後訪問://localhost:8000/str/archive

  6. 發現頁面會自動被跳轉到://www.zouwencong.com/archive/

  7. 證明路徑被截取並服務轉發成功

master-service – 轉髮指定地址並傳入參數

spring:
  #配置文件名稱,用來標識不同環境的配置。由 spring.profiles.active 的值來決定使用哪組配置。
  ##轉髮指定地址並傳入參數
  profiles: route_uri
  application:
    # 應用名稱
    name: gateway-master
  cloud:
    gateway:
      discovery:
        locator:
          # 是否和服務註冊與發現組件結合,設置為 true 後可以直接使用應用名稱調用服務
          enabled: true
      # 路由(routes:路由,它由唯一標識(ID)、目標服務地址(uri)、一組斷言(predicates)和一組過濾器組成(filters)。filters 不是必需參數。)
      routes:
      # 路由標識(id:標識,具有唯一性)   轉髮指定地址並傳入參數
      - id: route_uri
        # 目標服務地址(uri:地址,請求轉發後的地址)
        uri: //localhost:9000
        # 路由條件(predicates:斷言,匹配 HTTP 請求內容)
        predicates:
        ## 匹配 GET 請求
        - Method=GET
        # 過濾器(filters:過濾器,過濾規則)
        filters:
        ## 添加指定參數
        - AddRequestParameter=name, zwc
 
eureka:
  instance:
    # 使用 ip 代替實例名
    prefer-ip-address: true
    # 實例的主機名
    hostname: ${spring.cloud.client.ip-address}
    # 實例的 ID 規則
    instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
  client:
    serviceUrl:
      # 註冊中心地址
      defaultZone: //${eureka.instance.hostname}:8761/eureka/
 
logging:
  level:
    # log 級別
    org.springframework.cloud.gateway: debug
  1. 停止註冊中心工程(registry-service)和網關工程(master-service)

  2. 把 master-service – application.yml 配置文件中最上面的 spring.profiles.active 的值更改為 route_uri

  3. 上面配置文件內容意思是訪問的路徑 //localhost:8000/name (網關地址/name)

    會被轉發到 //localhost:9000/name(uri/name),並傳入 ‘name=zwc’ 參數(注意為 Get 請求)

  4. 啟動註冊中心工程(registry-service),網關工程(master-service)和服務工程 A(a-service)

  5. 項目啟動成功後訪問://localhost:8000/name

  6. 輸出內容:’My name is zwc. aaa’(通過網關轉發 – 參數有值)

  7. 打開新頁面訪問://localhost:9000/name

  8. 輸出內容:’My name is null. aaa’(直接訪問 – 參數沒有值)

  9. 證明轉髮指定地址並傳入參數成功

master-service – 轉髮指定服務並傳入參數

spring:
  #配置文件名稱,用來標識不同環境的配置。由 spring.profiles.active 的值來決定使用哪組配置。
  ##轉髮指定服務並傳入參數
  profiles: route_addRequestParameter
  application:
    # 應用名稱
    name: gateway-master
  cloud:
    gateway:
      discovery:
        locator:
          # 是否和服務註冊與發現組件結合,設置為 true 後可以直接使用應用名稱調用服務
          enabled: true
      # 路由(routes:路由,它由唯一標識(ID)、目標服務地址(uri)、一組斷言(predicates)和一組過濾器組成(filters)。filters 不是必需參數。)
      routes:
      # 路由標識(id:標識,具有唯一性)   轉髮指定服務並傳入參數
      - id: route_addRequestParameter
        # 目標服務地址(uri:地址,請求轉發後的地址)
        uri: lb://gateway-service
        # 路由條件(predicates:斷言,匹配 HTTP 請求內容)
        predicates:
        ## 匹配 GET 請求
        - Method=GET
        # 過濾器(filters:過濾器,過濾規則)
        filters:
        ## 添加指定參數
        - AddRequestParameter=age, three
 
eureka:
  instance:
    # 使用 ip 代替實例名
    prefer-ip-address: true
    # 實例的主機名
    hostname: ${spring.cloud.client.ip-address}
    # 實例的 ID 規則
    instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
  client:
    serviceUrl:
      # 註冊中心地址
      defaultZone: //${eureka.instance.hostname}:8761/eureka/
 
logging:
  level:
    # log 級別
    org.springframework.cloud.gateway: debug
  1. 停止註冊中心工程(registry-service),網關工程(master-service)和服務工程 A(a-service)

  2. 把 master-service – application.yml 配置文件中最上面的 spring.profiles.active 的值更改為 route_addRequestParameter

  3. 上面配置文件內容意思是訪問的路徑 //localhost:8000/age (網關地址/age)會被轉發到 //gateway-service/age(uri/age),並傳入 ‘age=three’ 參數(注意為 Get 請求)

  4. 注意此處的配置 uri: lb://gateway-service 與之前都有所不同,之前都是指定了明確的轉發地址,可以滿足單個服務轉發的需求,但是一般情況都會有多個服務,所以這裡是指定的服務名稱,格式為:lb://應用註冊服務名。

  5. 啟動註冊中心工程(registry-service),網關工程(master-service)和服務工程 A/B(a-service、b-service)

  6. 項目啟動成功後訪問://localhost:8000/age

  7. 這時可能會報錯 500.錯誤資訊為 ‘Unable to find instance for gateway-service’

  8. 這種情況不要慌張,只是服務還沒有被註冊到註冊中心,稍等片刻再訪問

  9. 多次訪問://localhost:8000/age

  10. 輪流輸出內容:’I am three years old this year. aaa’ 和 ‘I am three years old this year. bbb’

  11. 此時還通過網關達到了負載均衡的效果

  12. 證明轉髮指定服務並傳入參數成功

master-service – 熔斷

spring:
  #配置文件名稱,用來標識不同環境的配置。由 spring.profiles.active 的值來決定使用哪組配置。
  ##熔斷
  profiles: route_hystrix
  application:
    # 應用名稱
    name: gateway-master
  cloud:
    gateway:
      discovery:
        locator:
          # 是否和服務註冊與發現組件結合,設置為 true 後可以直接使用應用名稱調用服務
          enabled: true
      # 路由(routes:路由,它由唯一標識(ID)、目標服務地址(uri)、一組斷言(predicates)和一組過濾器組成(filters)。filters 不是必需參數。)
      routes:
      # 路由標識(id:標識,具有唯一性)   熔斷
      - id: route_hystrix
        # 目標服務地址(uri:地址,請求轉發後的地址)
        uri: lb://gateway-service
        # 路由條件(predicates:斷言,匹配 HTTP 請求內容)
        predicates:
        ## 匹配 GET 請求
        - Method=GET
        # 過濾器(filters:過濾器,過濾規則)
        filters:
        ## 添加指定參數
        - AddRequestParameter=age, three
        ## 熔斷
        - name: Hystrix
          args:
            name: fallbackcmd
            ### fallback 時調用的方法 //localhost:8000/fallback
            fallbackUri: forward:/fallback
 
eureka:
  instance:
    # 使用 ip 代替實例名
    prefer-ip-address: true
    # 實例的主機名
    hostname: ${spring.cloud.client.ip-address}
    # 實例的 ID 規則
    instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
  client:
    serviceUrl:
      # 註冊中心地址
      defaultZone: //${eureka.instance.hostname}:8761/eureka/
 
logging:
  level:
    # log 級別
    org.springframework.cloud.gateway: debug
  1. 停止註冊中心工程(registry-service),網關工程(master-service)和服務工程 A/B(a-service、b-service)

  2. 把 master-service – application.yml 配置文件中最上面的 spring.profiles.active 的值更改為 route_hystrix

  3. 上面配置文件內容意思是訪問的路徑 //localhost:8000/age (網關地址/age)會被轉發到 //gateway-service/age(uri/age),並傳入 ‘age=three’ 參數(注意為 Get 請求)

  4. 注意此處的配置 uri: lb://gateway-service 與之前都有所不同,之前都是指定了明確的轉發地址,可以滿足單個服務轉發的需求,但是一般情況都會有多個服務,所以這裡是指定的服務名稱,格式為:lb://應用註冊服務名。

  5. 此處還多配置了一個過濾器 ‘- name: Hystrix’(熔斷)

  6. 當請求服務出錯時,會調用 fallback,路徑為://localhost:8000/fallback (網關地址/fallback)

  7. 此時就需要如下前端控制器

master-service – 熔斷 – controller

package com.zwc.gateway.hystrix;
 
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
/**
 * @ClassName FallbackController
 * @Desc TODO   網關斷路器
 * @Date 2019/6/23 19:33
 * @Version 1.0
 */
@RestController
public class FallbackController {
 
    /*
     * @ClassName FallbackController
     * @Desc TODO   網關斷路器
     * @Date 2019/6/23 19:35
     * @Version 1.0
     */
    @RequestMapping("/fallback")
    public String fallback() {
        return "I'm Spring Cloud Gateway fallback.";
    }
 

}
8. 啟動註冊中心工程(registry-service),網關工程(master-service)和服務工程 A/B(a-service、b-service)

  1. 項目啟動成功後訪問://localhost:8000/age

  2. 輸出內容:’I’m Spring Cloud Gateway fallback.’

  3. 證明熔斷成功

master-service – 限流(重點,解決不生效問題)

spring:
  #配置文件名稱,用來標識不同環境的配置。由 spring.profiles.active 的值來決定使用哪組配置。
  ##限流
  profiles: route_requestRateLimiter
  redis:
    host: localhost
    port: 6379
    database: 0
  application:
    # 應用名稱
    name: gateway-master
  cloud:
    gateway:
      discovery:
        locator:
          # 是否和服務註冊與發現組件結合,設置為 true 後可以直接使用應用名稱調用服務
          enabled: true
      # 路由(routes:路由,它由唯一標識(ID)、目標服務地址(uri)、一組斷言(predicates)和一組過濾器組成(filters)。filters 不是必需參數。)
      routes:
      # 路由標識(id:標識,具有唯一性)   限流
      - id: route_requestRateLimiter
        # 目標服務地址(uri:地址,請求轉發後的地址)
        uri: lb://gateway-service
        # 路由條件(predicates:斷言,匹配 HTTP 請求內容)
        predicates:
        ## 匹配 GET 請求
        - Method=GET
        # 過濾器(filters:過濾器,過濾規則)
        filters:
        ## 添加指定參數
        - AddRequestParameter=age, three
        ## 限流
        - name: RequestRateLimiter
          args:
            ### 限流過濾器的 Bean 名稱
            key-resolver: '#{@uriKeyResolver}'
            ### 希望允許用戶每秒處理多少個請求
            redis-rate-limiter.replenishRate: 1
            ### 用戶允許在一秒鐘內完成的最大請求數
            redis-rate-limiter.burstCapacity: 3
 
eureka:
  instance:
    # 使用 ip 代替實例名
    prefer-ip-address: true
    # 實例的主機名
    hostname: ${spring.cloud.client.ip-address}
    # 實例的 ID 規則
    instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
  client:
    serviceUrl:
      # 註冊中心地址
      defaultZone: //${eureka.instance.hostname}:8761/eureka/
 
logging:
  level:
    # log 級別
    org.springframework.cloud.gateway: debug
  1. 停止註冊中心工程(registry-service),網關工程(master-service)和服務工程 A/B(a-service、b-service)

  2. 把 master-service – application.yml 配置文件中最上面的 spring.profiles.active 的值更改route_requestRateLimiter

  3. 上面配置文件內容意思是訪問的路徑 //localhost:8000/age (網關地址/age)會被轉發到 //gateway-service/age(uri/age),並傳入 ‘age=three’ 參數(注意為 Get 請求)

  4. 注意此處還需要配置 redis 的連接資訊

  5. 注意此處是結合 redis 實現的限流,所以 filter 過濾器的 name 必須為 RequestRateLimiter

  6. 並且通過實現 KeyResolver 類來自定義限流策略,如下

master-service – 限流 – 策略

package com.zwc.gateway.config.filters;
 
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
 
/**
 * @ClassName UriKeyResolver
 * @Desc TODO   Spring Cloud Gateway 網關限流過濾器
 * @Date 2019/6/23 17:59
 * @Version 1.0
 */
public class UriKeyResolver implements KeyResolver {
 
    /*
     * @ClassName UriKeyResolver
     * @Desc TODO   根據請求的 uri 限流
     * @Date 2019/6/29 17:25
     * @Version 1.0
     */
    @Override
    public Mono<String> resolve(ServerWebExchange exchange) {
        return Mono.just(exchange.getRequest().getURI().getPath());
    }
 
}
  1. 啟動本地 redis(redis-server.exe) 服務

  2. 啟動註冊中心工程(registry-service),網關工程(master-service)和服務工程 A/B(a-service、b-service)

  3. 項目啟動成功後訪問://localhost:8000/age

  4. 此時限流卻無論如何都不生效,原因有如下兩點

① redis-server 版本過低!我 Windows 本地是 redis-2.4.2 版本的,要用 3 以上的版本!!!

② 數據在 redis 中存儲的時間只有幾秒,所以得使用 monitor 指令來動態的觀察!!!

  1. 打開 redis-cli.exe,輸入命令 monitor

  2. 快速刷新地址://localhost:8000/age

  3. 頁面上會出現 429,redis-cli.exe 中會出現很多數據交互(request_rate_limiter.xxx 開頭的 key)

  4. 證明限流成功

master-service – 綜合

spring:
  #配置文件名稱,用來標識不同環境的配置。由 spring.profiles.active 的值來決定使用哪組配置。
  ##綜合
  profiles: route_all
  redis:
    host: localhost
    port: 6379
    database: 0
  application:
    # 應用名稱
    name: gateway-master
  cloud:
    gateway:
      discovery:
        locator:
          # 是否和服務註冊與發現組件結合,設置為 true 後可以直接使用應用名稱調用服務
          enabled: true
      # 路由(routes:路由,它由唯一標識(ID)、目標服務地址(uri)、一組斷言(predicates)和一組過濾器組成(filters)。filters 不是必需參數。)
      routes:
      # 路由標識(id:標識,具有唯一性)   綜合
      - id: route_all
        # 目標服務地址(uri:地址,請求轉發後的地址)
        uri: lb://gateway-service
        # 路由條件(predicates:斷言,匹配 HTTP 請求內容)
        predicates:
        ## 轉發地址格式為 uri/routeAll,/all 部分會被下面的過濾器給截取掉
        - Path=/all/routeAll
        ## 匹配 GET 請求
        - Method=GET
        # 過濾器(filters:過濾器,過濾規則)
        filters:
        ## 截取路徑位數
        - StripPrefix=1
        ## 添加指定參數
        - AddRequestParameter=pass, yes
        ## 熔斷
        - name: Hystrix
          args:
            name: fallbackcmd
            ### fallback 時調用的方法 //localhost:8000/fallback
            fallbackUri: forward:/fallback
        ## 限流
        - name: RequestRateLimiter
          args:
            ### 限流過濾器的 Bean 名稱
            key-resolver: '#{@uriKeyResolver}'
            ### 希望允許用戶每秒處理多少個請求
            redis-rate-limiter.replenishRate: 1
            ### 用戶允許在一秒鐘內完成的最大請求數
            redis-rate-limiter.burstCapacity: 3
 
eureka:
  instance:
    # 使用 ip 代替實例名
    prefer-ip-address: true
    # 實例的主機名
    hostname: ${spring.cloud.client.ip-address}
    # 實例的 ID 規則
    instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
  client:
    serviceUrl:
      # 註冊中心地址
      defaultZone: //${eureka.instance.hostname}:8761/eureka/
 
logging:
  level:
    # log 級別
    org.springframework.cloud.gateway: debug
  1. 停止註冊中心工程(registry-service),網關工程(master-service)和服務工程 A/B(a-service、b-service)

  2. 把 master-service – application.yml 配置文件中最上面的 spring.profiles.active 的值更改為 route_all

  3. 上面配置文件內容意思是訪問的路徑 //localhost:8000/all/routeAll (網關地址/all/routeAll)截取 /all 部分,會被轉發到 //gateway-service/routeAll(uri/routeAll),並傳入 ‘pass=yes’ 參數(注意為 Get 請求)

  4. 啟動註冊中心工程(registry-service),網關工程(master-service)和服務工程 A/B(a-service、b-service)

  5. 項目啟動成功後訪問://localhost:8000/all/routeAll

  6. 首先會返回 ‘I’m Spring Cloud Gateway fallback.’,因為服務還未被註冊到註冊中心

  7. 然後會返回 ‘{“msg”:”缺少憑證”,”code”:-1}’,因為配置了全局過濾器,如下

package com.zwc.gateway.config.filters;
 
import com.alibaba.fastjson.JSONObject;
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.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import org.springframework.core.io.buffer.DataBuffer;
 
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
 
/**
 * @ClassName TokenFilter
 * @Desc TODO   請求認證過濾器
 * @Date 2019/6/29 17:49
 * @Version 1.0
 */
public class TokenFilter implements GlobalFilter{
 
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 請求對象
        ServerHttpRequest request = exchange.getRequest();
        // 響應對象
        ServerHttpResponse response = exchange.getResponse();
 
        // 只有綜合路由才添加這個全局過濾器(routesId:route_all)
        // 如果請求路徑中不存在 routeAll 字元串
        if(request.getURI().toString().indexOf("routeAll") == -1){
            System.out.println("filter -> return");
            // 直接跳出
            return chain.filter(exchange);
        }
 
        // 從請求中獲取 token 參數
        String token = exchange.getRequest().getQueryParams().getFirst("token");
        // 如果為空,那麼將返回 401
        if (token == null || token.isEmpty()) {
 
            // 響應消息內容對象
            JSONObject message = new JSONObject();
            // 響應狀態
            message.put("code", -1);
            // 響應內容
            message.put("msg", "缺少憑證");
            // 轉換響應消息內容對象為位元組
            byte[] bits = message.toJSONString().getBytes(StandardCharsets.UTF_8);
            DataBuffer buffer = response.bufferFactory().wrap(bits);
            // 設置響應對象狀態碼 401
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            // 設置響應對象內容並且指定編碼,否則在瀏覽器中會中文亂碼
            response.getHeaders().add("Content-Type", "text/plain;charset=UTF-8");
            // 返迴響應對象
            return response.writeWith(Mono.just(buffer));
        }
        // 獲取請求地址
        String beforePath = request.getPath().pathWithinApplication().value();
        // 獲取響應狀態碼
        HttpStatus beforeStatusCode = response.getStatusCode();
        System.out.println("響應碼:" + beforeStatusCode + ",請求路徑:" + beforePath);
        // 請求前
        System.out.println("filter -> before");
        // 如果不為空,就通過
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            // 獲取請求地址
            String afterPath = request.getPath().pathWithinApplication().value();
            // 獲取響應狀態碼
            HttpStatus afterStatusCode = response.getStatusCode();
            System.out.println("響應碼:" + afterStatusCode + ",請求路徑:" + afterPath);
            // 響應後
            System.out.println("filter -> after");
        }));
    }
 
}
  1. 全局過濾器,不需要配置在配置文件中,作用於所有路由;只是這裡在處理前做了判斷,只有路徑中存在routeAll 字元串才到後續處理;並且處理分為請求前的處理,和響應後的處理

  2. 此時在地址://localhost:8000/all/routeAll 中添加 token 參數

  3. 訪問://localhost:8000/all/routeAll?token=123

  4. 輪流輸出內容:’Can I pass? yes! port:9000′ 和 ‘Can I pass? yes! port:9001’

  5. 觀察 gateway 工程的控制台,會有如下內容輸出

響應碼:null,請求路徑:/routeAll
filter -> before
響應碼:200,請求路徑:/routeAll
filter -> after
 13. 證明全局過濾器過濾成功

service 工程 – 項目結構

把多工程項目使用 IntelliJ IDEA 打開

1.把項目從 GitHub 中下載到你的本地

2.打開 IntelliJ IDEA

3.點擊 File -> Open

4.打開你下載到本地的項目目錄

5.springcloud-gateway -> springcloud-gateway-service(選擇打開此工程)

6.打開 service 工程後

7.再次點擊 File -> Project Structrue

8.選擇 Modules,點擊 ‘+’ 符號

9.點擊 Import Module

10.還是打開你下載到本地的項目目錄

11.springcloud-gateway -> springcloud-gateway-commons -> pom.xml

12.點擊 OK

13.點擊 Next,Finish

14.點擊 Apply,OK