• Spring Cloud框架学习-Spring Cloud Gateway


    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的实例,使用过滤器,可以在请求被路由前后对请求进行修改。

    和Zuul的对比:

    1. Zuul 是 Netflix 公司的开源产品,Spring Cloud Gateway 是 Spring 家族中的产品,可以和Spring 家族中的其他组件更好的融合。
    2. Zuul1 不支持长连接,例如 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.cloud</groupId>
    			<artifactId>spring-cloud-starter-gateway</artifactId>
    			<exclusions>
    				<exclusion>
    					<groupId>org.springframework.boot</groupId>
    					<artifactId>spring-boot-starter-hateoas</artifactId>
    				</exclusion>
    			</exclusions>
    		</dependency>
    
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-test</artifactId>
    			<scope>test</scope>
    		</dependency>
    	</dependencies>
    
    	<dependencyManagement>
    		<dependencies>
    			<dependency>
    				<groupId>org.springframework.cloud</groupId>
    				<artifactId>spring-cloud-dependencies</artifactId>
    				<version>${spring-cloud.version}</version>
    				<type>pom</type>
    				<scope>import</scope>
    			</dependency>
    		</dependencies>
    	</dependencyManagement>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    项目创建后,通过配置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();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

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

    在这里插入图片描述

    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
    
    • 1
    • 2
    • 3

    对应YML配置示例

    spring:
      cloud:
        gateway:
          routes:
            - id: test_route
            uri: http://httpbin.org
            predicates:
              - Path=/get
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2.3 服务化配置

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

    		<dependency>
    			<groupId>org.springframework.cloud</groupId>
    			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    		</dependency>
    
    • 1
    • 2
    • 3
    • 4

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

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

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

    在这里插入图片描述

    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]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    表示请求时间在 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    配置表示只给GET请求路由

    3.3 请求路径匹配

    spring:
      cloud:
        gateway:
          routes:
            - id: test_route
              uri: http://httpbin.org
              predicates:
                - Path=/2019/0612/{segment}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

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

    3.4 参数匹配

    spring:
      cloud:
        gateway:
          routes:
            - id: test_route
              uri: http://httpbin.org
              predicates:
                - Query=name
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

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

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

    spring:
      cloud:
        gateway:
          routes:
            - id: test_route
              uri: http://httpbin.org
              predicates:
                - Query=name,java.*
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

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

    spring:
      cloud:
        gateway:
          routes:
            - id: test_route
              uri: http://httpbin.org
              predicates:
                - Query=name,java.*
                - Path=/2019/0612/{segment}
                - Method=GET
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    3.5 Cookie匹配

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

    spring:
      cloud:
        gateway:
          routes:
            - id: test_route
              uri: http://httpbin.org
              predicates:
                - Cookie=username
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3.6 请求头Header匹配

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

    spring:
      cloud:
        gateway:
          routes:
            - id: test_route
              uri: http://httpbin.org
              predicates:
                - Header=X-Request-Id
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3.7 Host主机匹配

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

    spring:
      cloud:
        gateway:
          routes:
            - id: test_route
              uri: http://httpbin.org
              predicates:
                - Host=www.**.com
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3.8 远程地址RemoteAddr匹配

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

    spring:
      cloud:
        gateway:
          routes:
            - id: test_route
              uri: http://httpbin.org
              predicates:
                - RemoteAddr=192.168.1.1/24
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    4. Filter过滤器

    Spring Cloud Gateway中的过滤器分为两大类:GatewayFilter和GlobalFilter。

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

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

    在这里插入图片描述
    浏览器请求Gateway,实现转发到provider的test_get接口,并自动添加上参数。
    在这里插入图片描述
    请求test_get接口,已有参数的话会额外加上过滤器配置的参数。
    在这里插入图片描述

    4.2 StripPrefix GatewayFilter

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

    spring:
      cloud:
        gateway:
          routes:
          - id: test_route
            uri: http://localhost:8201
            predicates:
            - Path=/user-service/**
            filters:
            - StripPrefix=2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

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

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

    相当于请求该地址:

    http://localhost:8201/user/1
    
    • 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

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

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

    相当于请求该地址:

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

    4.4 Hystrix GatewayFilter

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

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

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
    
    • 1
    • 2
    • 3
    • 4

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

    @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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

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

    spring:
      cloud:
        gateway:
          routes:
            - id: hystrix_route
              uri: http://localhost:8201
              predicates:
                - Method=GET
              filters:
                - name: Hystrix
                  args:
                    name: fallback
                    fallbackUri: forward:/fallback
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    请求http://localhost:8080/1发现已经返回了服务降级的处理信息,因为http://localhost:8201/没有提供该接口。
    在这里插入图片描述

    4.5 RequestRateLimiter GatewayFilter

    RequestRateLimiter 过滤器可以用于限流,使用RateLimiter实现来确定是否允许当前请求继续进行,如果请求太大默认会返回HTTP 429-太多请求状态。

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

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
    </dependency>
    
    • 1
    • 2
    • 3
    • 4

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

    @Configuration
    public class RedisRateLimiterConfig {
    
        @Bean
        public KeyResolver ipKeyResolver() {
            return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    启动provider服务,注册到注册中心http://localhost:1111/eureka上,提供hello接口。频繁多次浏览器访问:http://localhost:8080/hello ,会返回状态码为429的错误;
    在这里插入图片描述

    参考:Spring Cloud Gateway:新一代API网关服务

  • 相关阅读:
    sql注入(5), sqlmap工具
    ElasticSearch - 解决ES的深分页问题 (游标 scroll)
    云原生Kubernetes: K8S 1.29版本 部署Nexus
    搞懂TypeScript的类型声明
    你听说过什么是代码本吗? (幽兰代码本初体验)
    【BOOST C++ 12 函数式编程】(3) Boost.Boost.Bind
    Python-scapy模块的使用
    同一个页面同一区域两个el-table在v-if下样式重叠问题
    Mysql进阶1
    Encrypt 加密/解密
  • 原文地址:https://blog.csdn.net/huangjhai/article/details/124544629