SpringCloudGateWay网关组件使用教程
使用的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是什么
- Gateway是在Spring生态系统之上构建的API网关服务,基于Spring,SpringBoot和ProjectReactor等技术
- Gateway旨在提供一种简单而有效的方式来对API进行路由,以及提供一些强大的过滤器功能,例如∶熔断、限流、重试等
网关的核心功能
- 鉴权
- 流量控制
- 熔断
- 日志监控
- 反向代理
Gateway和Zuul区别
- SpringCloudGateway作为SpringCloud生态系统中的网关,目标是替代Zuul
- SpringCloudGateway是基于SpringWebFlux框架实现的
- SpringWebFlux框架底层则使用了高性能的Reactor模式通信框架Netty,提升了网关性能
SpringCloudGateway基于SpringFramework(支持SpringWebFlux),ProjectReactor和SpringBoot进行构建,具有如下特性:
- 动态路由可以对路由指定Predicate(断言)和Filter(过滤器)
- 集成Hystrix的断路器功能
- 集成SpringCloud服务发现功能
- 请求限流功能支持路径重写
2.Gateway核心概念
- web请求,通过一些匹配条件,定位到真正的服务节点/微服务模块,在这个转发过程的前后,进行一些精细化控制
- predicate(断言):就是匹配条件
- filter(过滤器):可以理解为是网关的过滤机制,我们可以在请求前和请求后对数据进行改造。有了predicate和filter,再加上目标URL.就可以实现一个具体的路由
Route(路由)
路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由
Predicate(断言)
对HTTP请求中的所有内容(例如请求头或请求参数)进行匹配,如果请求与断言相匹配则进行路由
比如配置路径,- Path=/member/get/**
#断言,路径相匹配的进行路由转发,如果Http请求的路径不匹配,则不进行路由转发
Filter(过滤)
使用过滤器,可以在请求被路由前或者之后对请求进行处理
在对Http请求断言匹配成功后,可以通过网关的过滤机制,对Http请求处理,比如在请求前给请求数据包加上特定的参数color=blue
3.Spring Cloud GateWay应用实例
-
引入依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency>
-
配置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(); } }
-
创建主程序
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.使用服务发现功能,实现负载均衡
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验证接口
鉴权成功
鉴权失败