七、Spring Cloud Alibaba 路由网关(Gateway)

Spring Cloud Alibaba 路由网关(Gateway)

Spring Cloud Gateway 是 Spring 官方基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,Spring Cloud Gateway 旨在为微服务架构提供一种简单而有效的统一的 API 路由管理方式。Spring Cloud Gateway 作为 Spring Cloud 生态系中的网关,目标是替代 Netflix ZUUL,其不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控/埋点,和限流等。

image.png

Spring Cloud Gateway 功能特征

  • 基于 Spring Framework 5,Project Reactor 和 Spring Boot 2.0

  • 动态路由

  • Predicates 和 Filters 作用于特定路由

  • 集成 Hystrix 断路器

  • 集成 Spring Cloud DiscoveryClient

  • 易于编写的 Predicates 和 Filters

  • 限流

  • 路径重写

Spring Cloud Gateway 工程流程

image.png

客户端向 Spring Cloud Gateway 发出请求。然后在 Gateway Handler Mapping 中找到与请求相匹配的路由,将其发送到 Gateway Web Handler。Handler 再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。

过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前(pre)或之后(post)执行业务逻辑。

项目创建

  1. 创建一个名为idreamyou4cloud-gateway的模块,pom.xml配置如下:
<?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>idreamyou4cloud</artifactId>
        <groupId>cn.idreamyou</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>idreamyou4cloud-gateway</artifactId>
    <packaging>jar</packaging>

    <dependencies>
        <!--gateway 网关依赖,内置webflux 依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

        <!--注册中心客户端-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

Spring Cloud Gateway 是使用 netty+webflux 实现因此不需要再引入 web 模块

  1. 创建启动类:
package cn.idreamyou.idreamyou4cloud.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
 * 网关
 *
 * @author juning
 * @date 2020/9/14
 */
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }

}
  1. 编写配置文件,我们先来测试一个最简单的请求转发:
server:
  # 服务端口
  port: 8083

spring:
  application:
    # 应用名称,这里采用Maven项目的模块名
    name: @artifactId@
  cloud:
    nacos:
      # 注册重新nacos的地址
      server-addr: localhost:8848
    gateway:
      routes:
        - id: demo1
          uri: https://www.idreamyou.cn
          predicates:
            - Path=/s/about

management:
  endpoints:
    web:
      exposure:
        include: "*"

各字段含义如下:

  • id:我们自定义的路由 ID,保持唯一
  • uri:目标服务地址
  • predicates:路由条件,Predicate 接受一个输入参数,返回一个布尔值结果。该接口包含多种默认方法来将 Predicate 组合成其他复杂的逻辑(比如:与,或,非)。

上面这段配置的意思是,配置了一个 id 为 demo1 的路由规则,当访问地址 http://localhost:8083/s/about时会自动转发到地址:https://www.idreamyou.cn/s/about

配置完成启动项目即可在浏览器访问进行测试,当我们访问地址http://localhost:8083/s/about 时会展示页面展示如下:

image.png

上述整体项目结构如下:

image.png

更多的规则尝试

  1. 通过代码来实现转发功能:

先将关于gateway有关的配置注释掉:

server:
  # 服务端口
  port: 8083

spring:
  application:
    # 应用名称,这里采用Maven项目的模块名
    name: @artifactId@
  cloud:
    nacos:
      # 注册重新nacos的地址
      server-addr: localhost:8848
#    gateway:
#      routes:
#        - id: demo1
#          uri: https://www.idreamyou.cn
#          predicates:
#            - Path=/s/about

management:
  endpoints:
    web:
      exposure:
        include: "*"

在启动类GatewayApplication加入一个routeLocator() 来定制转发规则:

package cn.idreamyou.idreamyou4cloud.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;

/**
 * 网关
 *
 * @author juning
 * @date 2020/9/14
 */
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }

    @Bean
    public RouteLocator routeLocator(RouteLocatorBuilder routeLocatorBuilder) {
        return routeLocatorBuilder
                .routes()
                .route(
                        "code_demo",
                        predicateSpec -> predicateSpec
                                .path("/links")
                                .uri("https://www.idreamyou.cn")
                )
                .build();
    }

}

重启,浏览器访问http://localhost:8083/links :

image.png

上面配置了一个 id 为 code_demo 的路由,当访问地址http://localhost:8083/links时会自动转发到地址:https://www.idreamyou.cn/links和上面的转发效果一样,只是这里转发的是以项目地址/links格式的请求地址。

  1. 通过时间匹配

Predicate 支持设置一个时间,在请求进行转发的时候,可以通过判断在这个时间之前或者之后进行转发。比如我们现在设置只有在2020年09月15日才会转发到我的网站,在这之前不进行转发,我就可以这样配置:

server:
  # 服务端口
  port: 8083

spring:
  application:
    # 应用名称,这里采用Maven项目的模块名
    name: @artifactId@
  cloud:
    nacos:
      # 注册重新nacos的地址
      server-addr: localhost:8848
    gateway:
      routes:
        - id: demo1
          uri: https://www.idreamyou.cn
          predicates:
            - After=2020-09-15T22:51:00+08:00[Asia/Shanghai]

management:
  endpoints:
    web:
      exposure:
        include: "*"

Spring 是通过 ZonedDateTime 来对时间进行的对比,ZonedDateTime 是 Java 8 中日期时间功能里,用于表示带时区的日期与时间信息的类,ZonedDateTime 支持通过时区来设置时间,中国的时区是:Asia/Shanghai

After Route Predicate 是指在这个时间之后的请求都转发到目标地址。上面的示例是指,请求时间在 2020年09月15日22点51分00秒之后的所有请求都转发到地址https://www.idreamyou.cn+08:00是指时间和UTC时间相差八个小时,时间地区为Asia/Shanghai

添加完路由规则之后,访问地址http://localhost:8083会自动转发到https://www.idreamyou.cn

反之,如果将上述- After=2020-09-15T22:51:00+08:00[Asia/Shanghai]改为- Between=2020-09-15T22:51:00+08:00[Asia/Shanghai],那么当请求时间在 2020年09月15日22点51分00秒之后的所有请求都会抛出404

  1. 通过Host匹配

Host Route Predicate 接收一组参数,一组匹配的域名列表,这个模板是一个 ant 分隔的模板,用.号作为分隔符。它通过参数中的主机地址作为匹配规则。

server:
  # 服务端口
  port: 8083

spring:
  application:
    # 应用名称,这里采用Maven项目的模块名
    name: @artifactId@
  cloud:
    nacos:
      # 注册重新nacos的地址
      server-addr: localhost:8848
    gateway:
      routes:
        - id: host_demo
          uri: https://www.idreamyou.cn
          predicates:
            - Host=**.idreamyou.cn

management:
  endpoints:
    web:
      exposure:
        include: "*"

使用 curl 测试,命令行输入:

curl http://localhost:8083  -H "Host: haha.idreamyou.cn"
curl http://localhost:8083  -H "Host: xixi.idreamyou.cn"

经测试以上两种 host 均可匹配到 host_demo 路由,去掉 host 参数则会报 404 错误。

  1. 通过注册中心匹配
server:
  # 服务端口
  port: 8083

spring:
  application:
    # 应用名称,这里采用Maven项目的模块名
    name: @artifactId@
  cloud:
    nacos:
      # 注册重新nacos的地址
      server-addr: localhost:8848
    gateway:
      # 设置与服务注册发现组件结合,这样可以采用服务名的路由策略
      discovery:
        locator:
          enabled: true

management:
  endpoints:
    web:
      exposure:
        include: "*"

通过注册中心ID匹配其实配置很简单,只需要将spring.cloud.gateway.discovery.locator.enabled设置为true即可

注意:请求方式是 http://路由网关IP:路由网关Port/服务名/

依次启动idreamyou4cloud-upmsidreamyou4cloud-gateway,浏览器访问http://localhost:8083/idreamyou4cloud-upms/test/gateway :

image.png

再启动一个idreamyou4cloud-upms,然后多次刷新http://localhost:8083/idreamyou4cloud-upms/test/gateway,可以在浏览器中看到已默认实现负载均衡:

Hello Nacos Discovery gateway i am from port 8081
Hello Nacos Discovery gateway i am from port 8091

Spring Cloud Gateway 使用非常的灵活,可以根据不同的情况来进行路由分发,在实际项目中可以自由组合使用。

同时 Spring Cloud Gateway 还有更多很酷的功能,远远不止我上面列举的几种,比如 Filter 、熔断和限流等,这次只是一个简单的入门,之后我们继续学习 Spring Cloud Gateway 的高级功能。

上一篇 下一篇