SpringCloudGateWay网关组件使用教程

Spring Cloud GateWay官方文档

使用的springcolud版本是

    <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>2021.0.6</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

1.Spring Cloud GateWay是什么

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

网关的核心功能

  • 鉴权
  • 流量控制
  • 熔断
  • 日志监控
  • 反向代理

Gateway和Zuul区别

  • SpringCloudGateway作为SpringCloud生态系统中的网关,目标是替代Zuul
  • SpringCloudGateway是基于SpringWebFlux框架实现的
  • SpringWebFlux框架底层则使用了高性能的Reactor模式通信框架Netty,提升了网关性能

SpringCloudGateway基于SpringFramework(支持SpringWebFlux),ProjectReactor和SpringBoot进行构建,具有如下特性:

  • 动态路由可以对路由指定Predicate(断言)和Filter(过滤器)
  • 集成Hystrix的断路器功能
  • 集成SpringCloud服务发现功能
  • 请求限流功能支持路径重写

2.Gateway核心概念

  1. web请求,通过一些匹配条件,定位到真正的服务节点/微服务模块,在这个转发过程的前后,进行一些精细化控制
  2. predicate(断言):就是匹配条件
  3. filter(过滤器):可以理解为是网关的过滤机制,我们可以在请求前和请求后对数据进行改造。有了predicate和filter,再加上目标URL.就可以实现一个具体的路由

Route(路由)

路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由

Predicate(断言)

对HTTP请求中的所有内容(例如请求头或请求参数)进行匹配,如果请求与断言相匹配则进行路由

比如配置路径,- Path=/member/get/**#断言,路径相匹配的进行路由转发,如果Http请求的路径不匹配,则不进行路由转发

Filter(过滤)

使用过滤器,可以在请求被路由前或者之后对请求进行处理

在对Http请求断言匹配成功后,可以通过网关的过滤机制,对Http请求处理,比如在请求前给请求数据包加上特定的参数color=blue

3.Spring Cloud GateWay应用实例

  1. 引入依赖

            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-gateway</artifactId>
            </dependency>
    
  2. 配置Spring Cloud GateWay路由

    • 通过配置文件配置
    spring:
      application:
        name: member-gateway
      cloud:
        gateway:
          #配置路由,可以配置多组
          routes:
            #配置路由的id,需要全局唯一,查询数据使用该路由
            - id: member10001
              #路由转发的URI,最终转发的URL = URI + PATH
              uri: http://localhost:10001
              #配置路由的断言,满足条件时才进行路由
              predicates:
                #路径断言
                - Path=/member-gateway/member
                #方法断言
                - Method=GET
              filters:
                #重写路径,将请求路径中的member-gateway替换为member-provider,使用到正则表达式的命名捕获分组,语法格式:(?<捕获分组名称>pattern),引用捕获分组:$\{捕获分组名称}
                - RewritePath=/member-gateway/(?<segment>.*), /member-provider/$\{segment}
            #第二组路由,新增数据使用该路由
            - id: member10002
              uri: http://localhost:10002
              predicates:
                - Path=/member-gateway/member
                - Method=POST
              filters:
                - RewritePath=/member-gateway/(?<segment>.*), /member-provider/$\{segment}
    
    • 通过配置类配置
    package anyi.space.memberConsumer.config;
    
    import org.springframework.cloud.gateway.handler.predicate.GatewayPredicate;
    import org.springframework.cloud.gateway.route.RouteLocator;
    import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.HttpMethod;
    import org.springframework.web.server.ServerWebExchange;
    
    /**
     * @ProjectName: distributedSystemLearn
     * @FileName: GatewayConfig
     * @Author: 杨逸
     * @Data:2025/9/10 16:33
     * @Description: gateway配置类
     */
    @Configuration
    public class GatewayConfig {
        @Bean
        public RouteLocator myRouteLocator01(RouteLocatorBuilder builder){
            //根据配置文件改写为配置类的形式
            RouteLocatorBuilder.Builder routes = builder.routes();
            routes.route("member10001",r-> {
                return r
                        //路径断言
                        .path("/member-gateway/member")
                        .and()
                        //请求方法断言
                        .method(HttpMethod.GET)
                        //过滤器重写路径
                        .filters(fn ->{
                            //路径重写
                            return fn.rewritePath("/member-gateway/(?<segment>.*)","/member-provider/$\\{segment}");
                        })
                        //转发目标地址
                        .uri("http://localhost:10001");
    
            });
            return routes.build();
        }
        @Bean
        public RouteLocator myRouteLocator02(RouteLocatorBuilder builder){
            RouteLocatorBuilder.Builder routes = builder.routes();
            routes.route("member10002",r->{
                //自定义断言
                //r.predicate(new GatewayPredicate() {
                //    @Override
                //    public boolean test(ServerWebExchange serverWebExchange) {
                //        //断言是否为post请求方法
                //        HttpMethod.POST.equals(serverWebExchange.getRequest().getMethod());
                //        serverWebExchange.getRequest().getPath();
                //        return false;
                //    }
                //});
                return r.path("/member-gateway/member")
                        .and()
                        .method(HttpMethod.POST)
                        .filters(fn->{
                            return fn.rewritePath("/member-gateway/(?<segment>.*)","/member-provider/$\\{segment}");
                        }).uri("http://localhost:10002");
            });
            return routes.build();
        }
    }
    
    
  3. 创建主程序

    package anyi.space.memberConsumer;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    
    /**
     * @ProjectName: distributedSystemLearn
     * @FileName: MemberConsumerApplication
     * @Author: 杨逸
     * @Data:2025/4/13 20:05
     * @Description:
     */
    @EnableEurekaClient
    @SpringBootApplication()
    public class MemberGatewayApplication {
        public static void main(String[] args) {
            SpringApplication.run(MemberGatewayApplication.class,args);
        }
    }
    
    
  4. 验证

    通过网关查询数据

    通过网关新增数据

    image-20250518172028821

4.使用服务发现功能,实现负载均衡

spring:
  application:
    name: member-gateway
  cloud:
    gateway:
      discovery:
        locator:
          #开启服务发现功能
          enabled: true
      #配置路由,可以配置多组
      routes:
        #配置路由的id,需要全局唯一,查询数据使用该路由
        - id: member10001
          #路由转发的URI,最终转发的URL = URI + PATH
          #uri: http://localhost:10001
          #使用负载均衡
          uri: lb://member-service-provider
          #配置路由的断言,满足条件时才进行路由
          predicates:
            #路径断言
            - Path=/member-gateway/member
            #方法断言
            - Method=GET
          filters:
            #重写路径,将请求路径中的member-gateway替换为member-provider,使用到正则表达式的命名捕获分组,语法格式:(?<捕获分组名称>pattern),引用捕获分组:$\{捕获分组名称}
            - RewritePath=/member-gateway/(?<segment>.*), /member-provider/$\{segment}

5.内置的断言工厂

断言工厂就是不同断言方式产生的工厂,不同的断言工厂对应不同的断言规则,常见的用路径断言工厂,时间断言工厂,参数断言工厂

断言工厂可以组合使用,比如路径断言和参数断言可以一起使用

后置断言工厂(after)

只有在这个时间后的请求才能通过断言,时间的格式为ZonedDateTime

配置文件配置

spring:
  application:
    name: member-gateway
  cloud:
    gateway:
      discovery:
        locator:
          #开启服务发现功能
          enabled: true
      #配置路由,可以配置多组
      routes:
        #配置路由的id,需要全局唯一,查询数据使用该路由
        - id: member10001
          #使用负载均衡
          uri: lb://member-service-provider
          #配置路由的断言,满足条件时才进行路由
          predicates:
            #路径断言
            - Path=/member-gateway/member
            #后置时间断言,时间格式为ZonedDateTime
            - After=2025-09-10T19:01:03.749+08:00[Asia/Shanghai]

配置类配置

@Bean
    public RouteLocator myRouteLocator01(RouteLocatorBuilder builder){
        //根据配置文件改写为配置类的形式
        RouteLocatorBuilder.Builder routes = builder.routes();
        routes.route("member10001",r-> {
            ZonedDateTime zonedDateTime = ZonedDateTime.of(2025, 9, 10, 0, 0, 0, 0, ZoneId.systemDefault());
            return r
                    //路径断言
                    .path("/member-gateway/member")
                    .and()
                //后置时间断言,时间格式为ZonedDateTime
                    .after(zonedDateTime)
                    //过滤器重写路径
                    .filters(fn ->{
                        //路径重写
                        return fn.rewritePath("/member-gateway/(?<segment>.*)","/member-provider/$\\{segment}");
                    })
                    //转发目标地址
                    .uri("lb://member-service-provider");

        });
        return routes.build();
    }

前置断言工厂(Before)

只有在这个时间前的请求才能通过断言,时间的格式为ZonedDateTime

配置文件配置

spring:
  application:
    name: member-gateway
  cloud:
    gateway:
      discovery:
        locator:
          #开启服务发现功能
          enabled: true
      #配置路由,可以配置多组
      routes:
        #配置路由的id,需要全局唯一,查询数据使用该路由
        - id: member10001
          #使用负载均衡
          uri: lb://member-service-provider
          #配置路由的断言,满足条件时才进行路由
          predicates:
            #路径断言
            - Path=/member-gateway/member
            #前置时间断言,时间格式为ZonedDateTime
            - Before=2025-09-11T19:01:03.749+08:00[Asia/Shanghai]
          filters:
            #重写路径,将请求路径中的member-gateway替换为member-provider,使用到正则表达式的命名捕获分组,语法格式:(?<捕获分组名称>pattern),引用捕获分组:$\{捕获分组名称}
            - RewritePath=/member-gateway/(?<segment>.*), /member-provider/$\{segment}

配置类配置

@Bean
    public RouteLocator myRouteLocator01(RouteLocatorBuilder builder){
        //根据配置文件改写为配置类的形式
        RouteLocatorBuilder.Builder routes = builder.routes();
        routes.route("member10001",r-> {
            ZonedDateTime zonedDateTime = ZonedDateTime.of(2025, 9, 11, 0, 0, 0, 0, ZoneId.systemDefault());
            return r
                    //路径断言
                    .path("/member-gateway/member")
                    .and()
                    //请求方法断言
                    .method(HttpMethod.GET)
                    .and()
                    .before(zonedDateTime)
                    //.after(zonedDateTime)
                    //过滤器重写路径
                    .filters(fn ->{
                        //路径重写
                        return fn.rewritePath("/member-gateway/(?<segment>.*)","/member-provider/$\\{segment}");
                    })
                    //转发目标地址
                    .uri("lb://member-service-provider");

        });
        return routes.build();
    }

区间断言工厂

配置文件配置

spring:
  application:
    name: member-gateway
  cloud:
    gateway:
      discovery:
        locator:
          #开启服务发现功能
          enabled: true
      #配置路由,可以配置多组
      routes:
        #配置路由的id,需要全局唯一,查询数据使用该路由
        - id: member10001
          #路由转发的URI,最终转发的URL = URI + PATH
          #uri: http://localhost:10001
          #使用负载均衡
          uri: lb://member-service-provider
          #配置路由的断言,满足条件时才进行路由
          predicates:
            #路径断言
            - Path=/member-gateway/member
            #方法断言
            - Method=GET
            #时间区间断言,两个参数,只有在时间区间的的请求才能通过断言,时间格式为ZonedDateTime
            - Between=2025-09-10T19:01:03.749+08:00[Asia/Shanghai],2025-09-11T19:01:03.749+08:00[Asia/Shanghai]
          filters:
            #重写路径,将请求路径中的member-gateway替换为member-provider,使用到正则表达式的命名捕获分组,语法格式:(?<捕获分组名称>pattern),引用捕获分组:$\{捕获分组名称}
           

配置类配置

    public RouteLocator myRouteLocator01(RouteLocatorBuilder builder){
        //根据配置文件改写为配置类的形式
        RouteLocatorBuilder.Builder routes = builder.routes();
        routes.route("member10001",r-> {
            ZonedDateTime zonedDateTime = ZonedDateTime.of(2025, 9, 10, 0, 0, 0, 0, ZoneId.systemDefault());
            return r
                    //路径断言
                    .path("/member-gateway/member")
                    .and()
                    //请求方法断言
                    .method(HttpMethod.GET)
                    .and()
                    //时间区间断言
                    .between(zonedDateTime,zonedDateTime.plusDays(1))
                    //过滤器重写路径
                    .filters(fn ->{
                        //路径重写
                        return fn.rewritePath("/member-gateway/(?<segment>.*)","/member-provider/$\\{segment}");
                    })
                    //转发目标地址
                    .uri("lb://member-service-provider");

        });
        return routes.build();
    }

Cooike断言工厂

只有当请求的cookie中满足cookie断言才能匹配到请求转发路由

配置文件配置

spring:
  application:
    name: member-gateway
  cloud:
    gateway:
      discovery:
        locator:
          #开启服务发现功能
          enabled: true
      #配置路由,可以配置多组
      routes:
        #配置路由的id,需要全局唯一,查询数据使用该路由
        - id: member10001
          #路由转发的URI,最终转发的URL = URI + PATH
          #uri: http://localhost:10001
          #使用负载均衡
          uri: lb://member-service-provider
          #配置路由的断言,满足条件时才进行路由
          predicates:
            #路径断言
            - Path=/member-gateway/member
            #方法断言
            - Method=GET
            #cooike断言,格式为: "name,value",name为cookie的名称,value为cookie的值,value为正则表达式
            - Cookie=name,value
          filters:
            #重写路径,将请求路径中的member-gateway替换为member-provider,使用到正则表达式的命名捕获分组,语法格式:(?<捕获分组名称>pattern),引用捕获分组:$\{捕获分组名称}
           

配置类配置

public RouteLocator myRouteLocator01(RouteLocatorBuilder builder){
        //根据配置文件改写为配置类的形式
        RouteLocatorBuilder.Builder routes = builder.routes();
        routes.route("member10001",r-> {
            ZonedDateTime zonedDateTime = ZonedDateTime.of(2025, 9, 10, 0, 0, 0, 0, ZoneId.systemDefault());
            return r
                    //路径断言
                    .path("/member-gateway/member")
                    .and()
                    //请求方法断言
                    .method(HttpMethod.GET)
                    .and()
                    //cookie断言,第一个参数是cookie的name,第二个参数是cookie的值(正则表达式)
                    .cookie("name","value")
                    //过滤器重写路径
                    .filters(fn ->{
                        //路径重写
                        return fn.rewritePath("/member-gateway/(?<segment>.*)","/member-provider/$\\{segment}");
                    })
                    //转发目标地址
                    .uri("lb://member-service-provider");

        });
        return routes.build();
    }

请求头断言工厂

配置文件配置

spring:
  application:
    name: member-gateway
  cloud:
    gateway:
      discovery:
        locator:
          #开启服务发现功能
          enabled: true
      #配置路由,可以配置多组
      routes:
        #配置路由的id,需要全局唯一,查询数据使用该路由
        - id: member10001
          #路由转发的URI,最终转发的URL = URI + PATH
          #uri: http://localhost:10001
          #使用负载均衡
          uri: lb://member-service-provider
          #配置路由的断言,满足条件时才进行路由
          predicates:
            #路径断言
            - Path=/member-gateway/member
            #方法断言
            - Method=GET
            #Header断言,第一个参数为请求头的名称,第二个参数为请求头的值(正则表达式),格式为:name,value
            - Header=name,value
          filters:
            #重写路径,将请求路径中的member-gateway替换为member-provider,使用到正则表达式的命名捕获分组,语法格式:(?<捕获分组名称>pattern),引用捕获分组:$\{捕获分组名称}
            - RewritePath=/member-gateway/(?<segment>.*), /member-provider/$\{segment}       

配置类配置

public RouteLocator myRouteLocator01(RouteLocatorBuilder builder){
        //根据配置文件改写为配置类的形式
        RouteLocatorBuilder.Builder routes = builder.routes();
        routes.route("member10001",r-> {
            return r
                    //路径断言
                    .path("/member-gateway/member")
                    .and()
                    //请求方法断言
                    .method(HttpMethod.GET)
                    .and()
                    //header断言,第一个参数是header的name,第二个参数是header的值(正则表达式)
                    .header("name","value")
                    //过滤器重写路径
                    .filters(fn ->{
                        //路径重写
                        return fn.rewritePath("/member-gateway/(?<segment>.*)","/member-provider/$\\{segment}");
                    })
                    //转发目标地址
                    .uri("lb://member-service-provider");

        });
        return routes.build();
    }

Host断言工厂

配置文件

spring:
  application:
    name: member-gateway
  cloud:
    gateway:
      discovery:
        locator:
          #开启服务发现功能
          enabled: true
      #配置路由,可以配置多组
      routes:
        #配置路由的id,需要全局唯一,查询数据使用该路由
        - id: member10001
          #路由转发的URI,最终转发的URL = URI + PATH
          #uri: http://localhost:10001
          #使用负载均衡
          uri: lb://member-service-provider
          #配置路由的断言,满足条件时才进行路由
          predicates:
            #路径断言
            - Path=/member-gateway/member
            #方法断言
            - Method=GET
            #Host断言,参数为Ant格式的符合Host格式的字符串列表,多个则使用逗号分割
            - Host=localhost,127.0.0.1,**.space
          filters:
            #重写路径,将请求路径中的member-gateway替换为member-provider,使用到正则表达式的命名捕获分组,语法格式:(?<捕获分组名称>pattern),引用捕获分组:$\{捕获分组名称}
      

配置类

@Bean
    public RouteLocator myRouteLocator01(RouteLocatorBuilder builder){
        //根据配置文件改写为配置类的形式
        RouteLocatorBuilder.Builder routes = builder.routes();
        routes.route("member10001",r-> {
            return r
                    //路径断言
                    .path("/member-gateway/member")
                    .and()
                    //请求方法断言
                    .method(HttpMethod.GET)
                    .and()
                    //host断言,参数格式为Ant风格的host格式的字符串
                    .host("localhost","127.0.0.1","**.space")
                    //过滤器重写路径
                    .filters(fn ->{
                        //路径重写
                        return fn.rewritePath("/member-gateway/(?<segment>.*)","/member-provider/$\\{segment}");
                    })
                    //转发目标地址
                    .uri("lb://member-service-provider");

        });
        return routes.build();
    }

请求方式断言工厂

配置文件

spring:
  application:
    name: member-gateway
  cloud:
    gateway:
      discovery:
        locator:
          #开启服务发现功能
          enabled: true
      #配置路由,可以配置多组
      routes:
        #配置路由的id,需要全局唯一,查询数据使用该路由
        - id: member10001
          #路由转发的URI,最终转发的URL = URI + PATH
          #uri: http://localhost:10001
          #使用负载均衡
          uri: lb://member-service-provider
          #配置路由的断言,满足条件时才进行路由
          predicates:
            #路径断言
            - Path=/member-gateway/member
            #方法断言,参数为请求方法的字符串列表,多个则使用逗号分割
            - Method=GET
          filters:
            #重写路径,将请求路径中的member-gateway替换为member-provider,使用到正则表达式的命名捕获分组,语法格式:(?<捕获分组名称>pattern),引用捕获分组:$\{捕获分组名称}
    

配置类

public RouteLocator myRouteLocator01(RouteLocatorBuilder builder){
        //根据配置文件改写为配置类的形式
        RouteLocatorBuilder.Builder routes = builder.routes();
        routes.route("member10001",r-> {
            return r
                    //路径断言
                    .path("/member-gateway/member")
                    .and()
                    //请求方法断言
                    .method(HttpMethod.GET)
                    //过滤器重写路径
                    .filters(fn ->{
                        //路径重写
                        return fn.rewritePath("/member-gateway/(?<segment>.*)","/member-provider/$\\{segment}");
                    })
                    //转发目标地址
                    .uri("lb://member-service-provider");

        });
        return routes.build();
    }

路径断言工厂

配置文件

pring:
  application:
    name: member-gateway
  cloud:
    gateway:
      discovery:
        locator:
          #开启服务发现功能
          enabled: true
      #配置路由,可以配置多组
      routes:
        #配置路由的id,需要全局唯一,查询数据使用该路由
        - id: member10001
          #路由转发的URI,最终转发的URL = URI + PATH
          #uri: http://localhost:10001
          #使用负载均衡
          uri: lb://member-service-provider
          #配置路由的断言,满足条件时才进行路由
          predicates:
            #路径断言,参数为正则表达式字符串列表,多个则使用逗号分割,正则表达式中使用具名捕获分组,则捕获分组的值可以在过滤器中使用
            - Path=/member-gateway/member
          filters:
            #重写路径,将请求路径中的member-gateway替换为member-provider,使用到正则表达式的命名捕获分组,语法格式:(?<捕获分组名称>pattern),引用捕获分组:$\{捕获分组名称}
       

配置类

@Bean
    public RouteLocator myRouteLocator01(RouteLocatorBuilder builder){
        //根据配置文件改写为配置类的形式
        RouteLocatorBuilder.Builder routes = builder.routes();
        routes.route("member10001",r-> {
            return r
                    //路径断言
                    .path("/member-gateway/member")
                    .and()
                    //请求方法断言
                    .method(HttpMethod.GET)
                    //过滤器重写路径
                    .filters(fn ->{
                        //路径重写
                        return fn.rewritePath("/member-gateway/(?<segment>.*)","/member-provider/$\\{segment}");
                    })
                    //转发目标地址
                    .uri("lb://member-service-provider");

        });
        return routes.build();
    }

Query参数断言工厂

远程IP地址断言工厂

权重断言工厂

6.内置的过滤器工厂

添加请求头过滤器(AddRequestHeader GatewayFilter Factory)

在转发到匹配的路由前加上指定的请求头

配置文件配置

spring:
  application:
    name: member-gateway
  cloud:
    gateway:
      discovery:
        locator:
          #开启服务发现功能
          enabled: true
      #配置路由,可以配置多组
      routes:
        #配置路由的id,需要全局唯一,查询数据使用该路由
        - id: member10001
          #使用负载均衡
          uri: lb://member-service-provider
          #配置路由的断言,满足条件时才进行路由
          predicates:
            #路径断言,参数为正则表达式字符串列表,多个则使用逗号分割,正则表达式中使用具名捕获分组,则捕获分组的值可以在过滤器中使用
            - Path=/member-gateway/member
            #方法断言,参数为请求方法的字符串列表,多个则使用逗号分割
            - Method=GET
          filters:
            #重写路径,将请求路径中的member-gateway替换为member-provider,使用到正则表达式的命名捕获分组,语法格式:(?<捕获分组名称>pattern),引用捕获分组:$\{捕获分组名称}
            - RewritePath=/member-gateway/(?<segment>.*), /member-provider/$\{segment}
            #添加请求头,两个参数,第一个参数为请求头的名称,第二个参数为请求头的值,参数可以使用断言中定义的具名捕获分组
            - AddRequestHeader=headerName,headerValue

配置类配置

public RouteLocator myRouteLocator01(RouteLocatorBuilder builder){
        //根据配置文件改写为配置类的形式
        RouteLocatorBuilder.Builder routes = builder.routes();
        routes.route("member10001",r-> {
            return r
                    //路径断言
                    .path("/member-gateway/member")
                    .and()
                    //请求方法断言
                    .method(HttpMethod.GET)
                    //过滤器重写路径
                    .filters(fn ->{
                        //添加请求头
                        fn.addRequestHeader("headerName","配置类配置的-headValue");
                        //路径重写
                        fn.rewritePath("/member-gateway/(?<segment>.*)","/member-provider/$\\{segment}");
                        return fn;
                    })
                    //转发目标地址
                    .uri("lb://member-service-provider");

        });
        return routes.build();
    }

在服务提供方加入获取指定请求头的代码,验证

            //获取通过网关的添加请求头过滤器添加的请求头数据
            String headerName = request.getHeader("headerName");
            System.out.println("添加的数据为headerName = " + headerName);

验证日志输出

批量添加请求头过滤器工厂(AddRequestHeadersIfNotPresent GatewayFilter Factory)

新版本才支持这个

以键值对的形式添加请求头,键值对以冒号分割,可以一次添加多个键值对请求头,多个使用逗号分割

添加请求头时,只有匹配的请求头不存在时才会添加,存在时则不添加,保留原始的值

配置文件配置

配置类配置

添加请求参数过滤器工厂(AddRequestParameter GatewayFilter Factory)

配置文件配置

spring:
  application:
    name: member-gateway
  cloud:
    gateway:
      discovery:
        locator:
          #开启服务发现功能
          enabled: true
      #配置路由,可以配置多组
      routes:
        #配置路由的id,需要全局唯一,查询数据使用该路由
        - id: member10001
          #使用负载均衡
          uri: lb://member-service-provider
          #配置路由的断言,满足条件时才进行路由
          predicates:
            #路径断言,参数为正则表达式字符串列表,多个则使用逗号分割,正则表达式中使用具名捕获分组,则捕获分组的值可以在过滤器中使用
            - Path=/member-gateway/member
            #方法断言,参数为请求方法的字符串列表,多个则使用逗号分割
            - Method=GET
          filters:
            #重写路径,将请求路径中的member-gateway替换为member-provider,使用到正则表达式的命名捕获分组,语法格式:(?<捕获分组名称>pattern),引用捕获分组:$\{捕获分组名称}
            - RewritePath=/member-gateway/(?<segment>.*), /member-provider/$\{segment}
            #添加请求参数,两个参数,第一个参数为请求参数的名称,第二个参数为请求参数的值,参数可以使用断言中定义的具名捕获分组
            - AddRequestParameter=parameterName,parameterValue

配置类配置

public RouteLocator myRouteLocator01(RouteLocatorBuilder builder){
        //根据配置文件改写为配置类的形式
        RouteLocatorBuilder.Builder routes = builder.routes();
        routes.route("member10001",r-> {
            return r
                    //路径断言
                    .path("/member-gateway/member")
                    .and()
                    //请求方法断言
                    .method(HttpMethod.GET)
                    //过滤器重写路径
                    .filters(fn ->{
                        //添加请求参数
                        fn.addRequestParameter("parameterName","parameterValue");
                        //路径重写
                        fn.rewritePath("/member-gateway/(?<segment>.*)","/member-provider/$\\{segment}");
                        return fn;
                    })
                    //转发目标地址
                    .uri("lb://member-service-provider");

        });
        return routes.build();
    }

在服务提供放加入获取请求参数的代码

{
            //获取通过网关添加请求参数过滤器添加的参数数据
            String parameter = request.getParameter("parameterName");
            System.out.println("添加的参数parameter = " + parameter);
        }

验证添加的请求参数是否成功

添加响应头(AddResponseHeader GatewayFilter Factory)

配置文件配置

spring:
  application:
    name: member-gateway
  cloud:
    gateway:
      discovery:
        locator:
          #开启服务发现功能
          enabled: true
      #配置路由,可以配置多组
      routes:
        #配置路由的id,需要全局唯一,查询数据使用该路由
        - id: member10001
          #使用负载均衡
          uri: lb://member-service-provider
          #配置路由的断言,满足条件时才进行路由
          predicates:
            #路径断言,参数为正则表达式字符串列表,多个则使用逗号分割,正则表达式中使用具名捕获分组,则捕获分组的值可以在过滤器中使用
            - Path=/member-gateway/member
            #方法断言,参数为请求方法的字符串列表,多个则使用逗号分割
            - Method=GET
          filters:
            #重写路径,将请求路径中的member-gateway替换为member-provider,使用到正则表达式的命名捕获分组,语法格式:(?<捕获分组名称>pattern),引用捕获分组:$\{捕获分组名称}
            - RewritePath=/member-gateway/(?<segment>.*), /member-provider/$\{segment}
            #添加响应头,三个参数,第一个参数为响应头的名称,第二个参数为响应头的值,第三个参数为是否覆盖原有的响应头(默认为true),第三个参数为新版本新增
            - AddResponseHeader=responseHeaderName,responseHeaderValue

配置类配置

public RouteLocator myRouteLocator01(RouteLocatorBuilder builder){
        //根据配置文件改写为配置类的形式
        RouteLocatorBuilder.Builder routes = builder.routes();
        routes.route("member10001",r-> {
            return r
                    //路径断言
                    .path("/member-gateway/member")
                    .and()
                    //请求方法断言
                    .method(HttpMethod.GET)
                    //过滤器重写路径
                    .filters(fn ->{
                        //添加响应头
                        fn.addResponseHeader("responseHeaderName","responseHeaderValue");
                        //路径重写
                        fn.rewritePath("/member-gateway/(?<segment>.*)","/member-provider/$\\{segment}");
                        return fn;
                    })
                    //转发目标地址
                    .uri("lb://member-service-provider");

        });
        return routes.build();
    }

通过postman进行接口测试验证

7.自定义全局过滤器

模拟用户校验场景,当账号密码验证通过时才能进行路由转发

定义一个过滤器,实现GlobalFilter和Ordered接口

package anyi.space.memberConsumer.filter;

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.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;


/**
 * @ProjectName: distributedSystemLearn
 * @FileName: MyGlobalFilter
 * @Author: 杨逸
 * @Data:2025/9/12 17:27
 * @Description: 自定义全局过滤器
 * 实现鉴权场景,当用户名和密码满足要求时才能通过网关
 */
@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //获取请求头中的用户名和密码
        ServerHttpRequest request = exchange.getRequest();
        MultiValueMap<String, String> queryParams = request.getQueryParams();
        String username = queryParams.getFirst("username");
        String password = queryParams.getFirst("password");
        //判断用户名和密码是否正确
        if (!("yangyi".equals(username) && "password".equals(password))){
            System.out.println("鉴权失败");
            exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
            //没有通过校验,结束请求
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        //这里指定过滤器的优先级,数字越小,优先级越高
        return 0;
    }
}

通过postman验证接口

鉴权成功

鉴权失败