Spring Cloud框架学习-Spring Cloud Gateway

文章目录

    • 1. 简介
    • 2. 基本用法
      • 2.1 编码式配置路由
      • 2.2 配置文件配置路由
      • 2.3 服务化配置
    • 3. Predicate断言
      • 3.1 时间匹配
      • 3.2 请求方式匹配
      • 3.3 请求路径匹配
      • 3.4 参数匹配
      • 3.5 Cookie匹配
      • 3.6 请求头Header匹配
      • 3.7 Host主机匹配
      • 3.8 远程地址RemoteAddr匹配
      • 3.8 权重匹配
    • 4. Filter过滤器
      • 4.1 AddRequestParameter GatewayFilter
      • 4.2 StripPrefix GatewayFilter
      • 4.3 PrefixPath GatewayFilter
      • 4.4 Hystrix GatewayFilter
      • 4.5 RequestRateLimiter GatewayFilter

1. 简介

Spring Cloud Gateway是在Spring生态系统之上构建的API网关服务,基于Spring 5,Spring Boot 2和 Project Reactor等技术。Gateway旨在提供一种简单而有效的方式来对API进行路由,以及提供一些强大的过滤器功能, 例如:熔断、限流、重试等。

Spring Cloud Gateway 具有如下特性:

  • 基于Spring Framework 5, Project Reactor 和 Spring Boot 2.0 进行构建;
  • 动态路由:能够匹配任何请求属性;
  • 可以对路由指定 Predicate(断言)和 Filter(过滤器);
  • 集成Hystrix的断路器功能;
  • 集成 Spring Cloud 服务发现功能;
  • 易于编写的 Predicate(断言)和 Filter(过滤器);
  • 请求限流功能;
  • 支持路径重写。

Spring Cloud Gateway的重要的三大概念:

  • Route(路由):路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由;
  • Predicate(断言):指的是Java 8 的 Function Predicate。输入类型是Spring框架中的ServerWebExchange。这使开发人员可以匹配HTTP请求中的所有内容,例如请求头或请求参数。如果请求与断言相匹配,则进行路由;
  • Filter(过滤器):指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前后对请求进行修改。

Spring Cloud Gateway工作原理示例图:
Spring Cloud框架学习-Spring Cloud Gateway_第1张图片
客户端向 Spring Cloud Gateway 发出请求,如果请求与网关程序定义的路由匹配,则该请求就会被发送到网关 Web 处理程序,此时处理程序运行特定的请求过滤器链。

过滤器之间用虚线分开的原因是过滤器可能会在发送代理请求的之前和之后执行逻辑。所有 pre 过滤器逻辑先执行,然后执行代理请求;代理请求完成后,再执行 post 过滤器逻辑。

和Zuul的对比:

  1. Zuul 是 Netflix 公司的开源项目,Spring Cloud Gateway 是 Spring 家族中的产品,可以和Spring 家族中的其他组件更好的融合。
  2. Zuul 1.x基于Servlet 2. 5使用阻塞架构,使用的是阻塞式的 API,不支持长连接,例如Websocket。
  3. Spring Cloud Gateway 支持限流。
  4. Spring Cloud Gateway 基于 Netty 来开发,实现了异步和非阻塞,占用资源更小,性能强于Zuul。

2. 基本用法

Spring Cloud Gateway 支持两种不同的配置路由的方式:编码式和yml文件配置

2.1 编码式配置路由

创建Spring Boot项目,添加Spring Cloud Gateway依赖:

	<dependencies>
		<dependency>
			<groupId>org.springframework.cloudgroupId>
			<artifactId>spring-cloud-starter-gatewayartifactId>
			<exclusions>
				<exclusion>
					<groupId>org.springframework.bootgroupId>
					<artifactId>spring-boot-starter-hateoasartifactId>
				exclusion>
			exclusions>
		dependency>

		<dependency>
			<groupId>org.springframework.bootgroupId>
			<artifactId>spring-boot-starter-testartifactId>
			<scope>testscope>
		dependency>
	dependencies>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloudgroupId>
				<artifactId>spring-cloud-dependenciesartifactId>
				<version>${spring-cloud.version}version>
				<type>pomtype>
				<scope>importscope>
			dependency>
		dependencies>
	dependencyManagement>

项目创建后,通过配置RouteLocator实现请求转发

@SpringBootApplication
public class DemoApplication {

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

	@Bean
    RouteLocator routeLocator(RouteLocatorBuilder builder){
        return  builder.routes().route("test_route", r -> r.path("/get").uri("http://httpbin.org")).build();
    }
}

配置完成后,重启项目,请求http://localhost:8080/get

Spring Cloud框架学习-Spring Cloud Gateway_第2张图片

2.2 配置文件配置路由

对应properties配置示例

spring.cloud.gateway.routes[0].id=test_route
spring.cloud.gateway.routes[0].uri=http://httpbin.org
spring.cloud.gateway.routes[0].predicates[0]=Path=/get

对应YML配置示例

spring:
  cloud:
    gateway:
      routes:
        - id: test_route
        uri: http://httpbin.org
        predicates:
          - Path=/get

2.3 服务化配置

在Gateway项目上添加依赖,注册Gateway到Eureka上。

		<dependency>
			<groupId>org.springframework.cloudgroupId>
			<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
		dependency>

配置文件中添加注册中心配置,并开启自动代理

spring:
  cloud:
    gateway:
      routes:
        - id: test_route
          uri: http://httpbin.org
          predicates:
            - Path=/get
      discovery:
        locator:
          enabled: true # 开启自动代理
  application:
    name: gateway
eureka:
  client:
    service-url:
      defaultZone: http://localhost:1111/eureka
logging:
  level:
    org.springframework.cloud.gateway: debug

启动Eureka服务,启动Gateway和provider(服务提供者)服务,注册Gateway和provider服务到Eureka注册中心上。
在这里插入图片描述
provider服务的端口号为1113,Gateway的端口为8080.下面通过Gateway访问provider服务的hello接口

Spring Cloud框架学习-Spring Cloud Gateway_第3张图片

3. Predicate断言

Spring Cloud Gateway将路由匹配作为Spring WebFlux HandlerMapping基础架构的一部分。Spring Cloud Gateway包括许多内置的Route Predicate工厂( 包括时间匹配,请求方式匹配,请求路径匹配,参数匹配等)。所有这些Predicate都与HTTP请求的不同属性匹配。多个Route Predicate工厂可以进行组合,下面我们来介绍一些常用的Route Predicate。

3.1 时间匹配

spring:
  cloud:
    gateway:
      routes:
        - id: test_route
          uri: http://httpbin.org
          predicates:
            - After=2021-01-01T01:01:01+08:00[Asia/Shanghai]

表示请求时间在 2021-01-01T01:01:01+08:00[Asia/Shanghai] 时间之后才会被路由。

除了 After 之外,还有两个关键字:

  • Before,表示在某个时间点之前的请求匹配到该路由
  • Between,表示在两个时间点之间的请求匹配到该路由,两个时间点用 , 隔开

3.2 请求方式匹配

spring:
  cloud:
    gateway:
      routes:
        - id: test_route
          uri: http://httpbin.org
          predicates:
            - Method=GET

配置表示只给GET请求路由

3.3 请求路径匹配

spring:
  cloud:
    gateway:
      routes:
        - id: test_route
          uri: http://httpbin.org
          predicates:
            - Path=/2019/0612/{segment}

表示路径满足 /2019/0612/ 这个规则,都会被进行转发

3.4 参数匹配

spring:
  cloud:
    gateway:
      routes:
        - id: test_route
          uri: http://httpbin.org
          predicates:
            - Query=name

表示请求中一定要有 name 参数才会进行转发,否则不会进行转发,也可以指定参数和参数的值。

例如参数的key为name,value必须要以java开始:

spring:
  cloud:
    gateway:
      routes:
        - id: test_route
          uri: http://httpbin.org
          predicates:
            - Query=name,java.*

上面多种匹配方式也可以组合使用

spring:
  cloud:
    gateway:
      routes:
        - id: test_route
          uri: http://httpbin.org
          predicates:
            - Query=name,java.*
            - Path=/2019/0612/{segment}
            - Method=GET

3.5 Cookie匹配

带有指定Cookie的请求会匹配该路由。

spring:
  cloud:
    gateway:
      routes:
        - id: test_route
          uri: http://httpbin.org
          predicates:
            - Cookie=username

3.6 请求头Header匹配

带有指定Cookie的请求会匹配该路由。如下带有请求头为"X-Request-Id:test123"的请求可以匹配该路由。

spring:
  cloud:
    gateway:
      routes:
        - id: test_route
          uri: http://httpbin.org
          predicates:
            - Header=X-Request-Id

3.7 Host主机匹配

带有指定Host的请求会匹配该路由。如下带有Host:www.baidu.com的请求会匹配到该路由

spring:
  cloud:
    gateway:
      routes:
        - id: test_route
          uri: http://httpbin.org
          predicates:
            - Host=www.**.com

3.8 远程地址RemoteAddr匹配

从指定远程地址发起的请求可以匹配该路由。

spring:
  cloud:
    gateway:
      routes:
        - id: test_route
          uri: http://httpbin.org
          predicates:
            - RemoteAddr=192.168.1.1/24

3.8 权重匹配

使用权重来路由相应请求,以下表示有80%的请求会被路由到localhost:8201,20%会被路由到localhost:8202。

spring:
  cloud:
    gateway:
      routes:
      - id:weight_high
        uri:http://localhost:8201
        predicates:
        - Weight=group1,8
      - id: weight_low
        uri: http://localhost:8202
        predicates:
        - Weight=group1,2

4. Filter过滤器

Spring Cloud Gateway中的过滤器分为两大类:全局过滤器GlobalFilter和路由过滤器RouteFilter。下面介绍常用的几个过滤器。

4.1 AddRequestParameter GatewayFilter

使用AddRequestParameter过滤器,给/test_get请求自动额外添加参数

spring:
  cloud:
    gateway:
      routes:
        - id: test_route
          uri: lb://provider
          filters:
            - AddRequestParameter=name,robot
          predicates:
            - Path=/test_get

uri: lb://provider的作用是开启负载均衡功能,provider服务提供接口/test_get

Spring Cloud框架学习-Spring Cloud Gateway_第4张图片
浏览器请求Gateway,实现转发到provider的test_get接口,并自动添加上参数。
Spring Cloud框架学习-Spring Cloud Gateway_第5张图片
请求test_get接口,已有参数的话会额外加上过滤器配置的参数。
Spring Cloud框架学习-Spring Cloud Gateway_第6张图片

4.2 StripPrefix GatewayFilter

StripPrefix GatewayFilter是对指定数量的路径前缀进行去除的过滤器。

spring:
  cloud:
    gateway:
      routes:
      - id: test_route
        uri: http://localhost:8201
        predicates:
        - Path=/user-service/**
        filters:
        - StripPrefix=2

StripPrefix=2配置会把以/user-service/开头的请求的路径去除两位,即请求

http://localhost:9201/user-service/a/user/1

相当于请求该地址:

http://localhost:8201/user/1

4.3 PrefixPath GatewayFilter

PrefixPath GatewayFilter会对原有路径进行增加操作的过滤器。

spring:
  cloud:
    gateway:
      routes:
      - id: test_route
        uri: http://localhost:8201
        predicates:
        - Path=/user-service/**
        filters:
        - PrefixPath=/user

配置请求前缀为/user-service/的请求添加/user路径前缀,即请求

http://localhost:9201/user-service/1

相当于请求该地址:

http://localhost:8201/user-service/user/1

4.4 Hystrix GatewayFilter

Hystrix 过滤器允许我们将断路器功能添加到网关路由中,使服务免受级联故障的影响,并提供服务降级处理。

首先在pom.xml中添加Hystrix的相关依赖,开启断路器功能

<dependency>
    <groupId>org.springframework.cloudgroupId>
    <artifactId>spring-cloud-starter-netflix-hystrixartifactId>
dependency>

添加相关服务降级的处理类

@RestController
public class FallbackController {


    @GetMapping("/fallback")
    public Object fallback() {
        Map<String,Object> result = new HashMap<>();
        result.put("data",null);
        result.put("message","get request fallback!");
        result.put("code",500);
        return result;
    }
}

在配置文件中添加相关配置:当路由出错时会转发到服务降级处理的控制器上。

spring:
  cloud:
    gateway:
      routes:
        - id: hystrix_route
          uri: http://localhost:8201
          predicates:
            - Method=GET
          filters:
            - name: Hystrix
              args:
                name: fallback
                fallbackUri: forward:/fallback

请求http://localhost:8080/1发现已经返回了服务降级的处理信息,因为http://localhost:8201/没有提供该接口。
Spring Cloud框架学习-Spring Cloud Gateway_第7张图片

4.5 RequestRateLimiter GatewayFilter

RequestRateLimiter 过滤器可以用于限流,使用RateLimiter实现来确定是否允许当前请求继续进行,如果请求太频繁默认会返回HTTP 429 - Too Many Requests响应。

在pom.xml中添加相关依赖:

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-data-redis-reactiveartifactId>
dependency>

添加限流策略的配置类,提供策略ipKeyResolver根据访问IP进行限流。

@Configuration
public class RedisRateLimiterConfig {

    @Bean
    public KeyResolver ipKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
    }
}

在yml配置文件中添加Redis和RequestRateLimiter的配置,这里配置对所有的GET请求都进行了按IP来限流的操作。

spring:
  redis:
    host: localhost
    password: 123
    port: 6379
  cloud:
    gateway:
      routes:
        - id: test_route
          uri: lb://provider
          filters:
            - AddRequestParameter=name,robot
          predicates:
            - Path=/test_get
        - id: hystrix_route
          uri: http://localhost:8201
          predicates:
            - Method=GET
          filters:
            - name: Hystrix
              args:
                name: fallbackcmd
                fallbackUri: forward:/fallback
        - id: requestratelimiter_route
          uri: http://localhost:1113
          predicates:
            - Method=GET
          filters:
            - name: RequestRateLimiter
              args:
                #每秒允许处理的请求数量
                redis-rate-limiter.replenishRate: 1
                #每秒最大处理的请求数量
                redis-rate-limiter.burstCapacity: 2
                #限流策略,对应策略的Bean
                key-resolver: "#{@ipKeyResolver}"

      discovery:
        locator:
          enabled: true # 开启自动代理
  application:
    name: gateway
eureka:
  client:
    service-url:
      defaultZone: http://localhost:1111/eureka
logging:
  level:
    org.springframework.cloud.gateway: debug

``
RequestRateLimiter使用的算法是令牌桶算法,令牌桶算法介绍

令牌桶算法

RequestRateLimiter的配置说明:

  • filter名称必须是“RequestRateLimiter”
  • redis-rate-limiter.replenishRate:允许用户每秒处理多少个请求。这是令牌桶的填充速率。
  • redis-rate-limiter.burstCapacity:令牌桶的容量,允许在一秒钟内完成的最大请求数。这是令牌桶可以保存的令牌数。
  • redis-rate-limiter.requestedTokens: 是每个请求消耗多少个令牌,默认是1。
  • key-resolver:使用SpEL表达式按名称引用bean。

下面进行测试,启动provider服务,注册到注册中心http://localhost:1111/eureka上,提供hello接口。频繁多次浏览器访问:http://localhost:8080/hello ,会返回状态码为429的错误;
Spring Cloud框架学习-Spring Cloud Gateway_第8张图片
查看Redis中的Key:
在这里插入图片描述

  • 大括号中就是限流Key,这里我们测试的是ip限流,所以key是IP,本地访问的就是0:0:0:0:0:0:0:1/

  • timestamp:存储的是当前时间的秒数,也就是System.currentTimeMillis() / 1000或者Instant.now().getEpochSecond()
    在这里插入图片描述

  • tokens:存储的是当前这秒钟的对应的可用的令牌数量
    在这里插入图片描述

我们不仅可以通过ip进行限流,还可以根据ServerHttpRequest的其他参数进行限流
Spring Cloud框架学习-Spring Cloud Gateway_第9张图片

例如根据请求参数中的username进行限流

@Bean
KeyResolver userKeyResolver() {
    return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
}

参考:
1.Spring Cloud Gateway官方文档
2.Spring Cloud Gateway:新一代API网关服务

你可能感兴趣的:(Spring,Cloud,spring,cloud,学习,java)