当前位置:   article > 正文

SpringCloud之服务网关Gateway_spring-cloud-starter-gateway

spring-cloud-starter-gateway

前言
  SpringCloud 是微服务中的翘楚,最佳的落地方案。

  Spring Cloud Gateway 是 Spring Cloud 新推出的网关框架,之前是 Netflix Zuul。网关通常在项目中为了简化

  前端的调用逻辑,同时也简化内部服务之间互相调用的复杂度;具体作用就是转发服务,接收并转发所有内外

  部的客户端调用;其他常见的功能还有权限认证,限流控制等等。

  本博客会提到网关的基本转发功能,熔断功能,限流功能以及功能的综合使用。

源码
  GitHub地址:https://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="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">
    <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="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">
    <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: http://${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. 项目启动成功后访问 http://localhost:8761/ 即可看到 eureka-server 主页面

 

  注:由于服务工程 A 和服务工程 B 除端口不一致以外,其他代码基本一致,所以服务工程 B 不再赘述

a-service(服务工程 A)
a-service - POM 文件
<?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">
    <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: http://${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. 刷新 http://localhost:8761/(注册中心)可以看到服务已经被注册进来了

  2. 项目启动成功后访问:http://localhost:9000/hello

  3. 输出内容:'Hello!I'm a. port:9000'

  4. 同样启动服务工程 B后,刷新 http://localhost:8761/(注册中心)

  5. 项目启动成功后访问:http://localhost:9001/hello

  6. 输出内容:'Hello!I'm b. port:9001'

  7. 其他接口是下面网关服务启动后转发调用的,也是本博客的重头戏

 

master-service(网关)
master-service - POM 文件
<?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">
    <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: https://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: http://${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: https://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: http://${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: http://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: http://${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: http://${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 时调用的方法 http://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: http://${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: http://${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 时调用的方法 http://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: http://${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: https://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. 上面配置文件内容意思是当访问 http://localhost:8000/archive (网关地址/archive)

      会被转发到 https://www.zouwencong.com/archive/ (uri/archive)

  4. 启动注册中心工程(registry-service)和网关工程(master-service)

  5. 项目启动成功后访问:http://localhost:8000/archive

  6. 发现页面会自动被跳转到:https://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: https://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: http://${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. 上面配置文件内容意思是访问的路径 http://localhost:8000/str/archive (网关地址/str/archive)截取 /str 部分,

      截取后被转发到 https://www.zouwencong.com/archive/ (uri/archive)

  4. 启动注册中心工程(registry-service)和网关工程(master-service)

  5. 项目启动成功后访问:http://localhost:8000/str/archive

  6. 发现页面会自动被跳转到:https://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: http://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: http://${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. 上面配置文件内容意思是访问的路径 http://localhost:8000/name (网关地址/name)

      会被转发到 http://localhost:9000/name(uri/name),并传入 'name=zwc' 参数(注意为 Get 请求)

  4. 启动注册中心工程(registry-service),网关工程(master-service)和服务工程 A(a-service)

  5. 项目启动成功后访问:http://localhost:8000/name

  6. 输出内容:'My name is zwc. aaa'(通过网关转发 - 参数有值)

  7. 打开新页面访问:http://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: http://${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. 上面配置文件内容意思是访问的路径 http://localhost:8000/age (网关地址/age)

      会被转发到 http://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. 项目启动成功后访问:http://localhost:8000/age

  7. 这时可能会报错 500.错误信息为 'Unable to find instance for gateway-service'

  8. 这种情况不要慌张,只是服务还没有被注册到注册中心,稍等片刻再访问

  9. 多次访问:http://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 时调用的方法 http://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: http://${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. 上面配置文件内容意思是访问的路径 http://localhost:8000/age (网关地址/age)

      会被转发到 http://gateway-service/age(uri/age),并传入 'age=three' 参数(注意为 Get 请求)

  4. 注意此处的配置 uri: lb://gateway-service 与之前都有所不同,之前都是指定了明确的转发地址,可以满足

      单个服务转发的需求,但是一般情况都会有多个服务,所以这里是指定的服务名称,格式为:lb://应用注册

      服务名。

  5. 此处还多配置了一个过滤器 '- name: Hystrix'(熔断)

  6. 当请求服务出错时,会调用 fallback,路径为:http://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)

  9. 项目启动成功后访问:http://localhost:8000/age

 10. 输出内容:'I'm Spring Cloud Gateway fallback.'

 11. 证明熔断成功

 

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: http://${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. 上面配置文件内容意思是访问的路径 http://localhost:8000/age (网关地址/age)

      会被转发到 http://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());
    }
 
}
  7. 启动本地 redis(redis-server.exe) 服务

  8. 启动注册中心工程(registry-service),网关工程(master-service)和服务工程 A/B(a-service、b-service)

  9. 项目启动成功后访问:http://localhost:8000/age

 10. 此时限流却无论如何都不生效,原因有如下两点

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

② 数据在 redis 中存储的时间只有几秒,所以得使用 monitor 指令来动态的观察!!!

 11. 打开 redis-cli.exe,输入命令 monitor 

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

 13. 页面上会出现 429,redis-cli.exe 中会出现很多数据交互(request_rate_limiter.xxx 开头的 key)

 14. 证明限流成功

 

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 时调用的方法 http://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: http://${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. 上面配置文件内容意思是访问的路径 http://localhost:8000/all/routeAll (网关地址/all/routeAll)截取 /all 部分,

      会被转发到 http://gateway-service/routeAll(uri/routeAll),并传入 'pass=yes' 参数(注意为 Get 请求)

  4. 启动注册中心工程(registry-service),网关工程(master-service)和服务工程 A/B(a-service、b-service)

  5. 项目启动成功后访问:http://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");
        }));
    }
 
}
  8. 全局过滤器,不需要配置在配置文件中,作用于所有路由;只是这里在处理前做了判断,只有路径中存在

      routeAll 字符串才到后续处理;并且处理分为请求前的处理,和响应后的处理

  9. 此时在地址:http://localhost:8000/all/routeAll 中添加 token 参数

 10. 访问:http://localhost:8000/all/routeAll?token=123

 11. 轮流输出内容:'Can I pass? yes! port:9000' 和 'Can I pass? yes! port:9001'

 12. 观察 gateway 工程的控制台,会有如下内容输出

响应码:null,请求路径:/routeAll
filter -> before
响应码:200,请求路径:/routeAll
filter -> after
 13. 证明全局过滤器过滤成功

 

service 工程 - 项目结构


 

把多工程项目使用 IntelliJ IDEA 打开
把项目从 GitHub 中下载到你的本地
打开 IntelliJ IDEA 
点击 File -> Open
打开你下载到本地的项目目录
springcloud-gateway -> springcloud-gateway-service(选择打开此工程)
打开 service 工程后
再次点击 File -> Project Structrue
选择 Modules,点击 '+' 符号
点击 Import  Module
还是打开你下载到本地的项目目录
springcloud-gateway -> springcloud-gateway-commons -> pom.xml
点击 OK
点击 Next,Finish
点击 Apply,OK
 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/301472
推荐阅读
相关标签
  

闽ICP备14008679号