分布式微服务 - 3.服务网关 - 4.Gateway
项目示例:
- 项目示例 - 3.服务网关 - 3.Gateway
内容提要:
- 基本使用:配置方式、代码方式
- 内置断言、自定义断言
- 内置局部过滤器、自定义内置和全局过滤器
文档:
基本使用
配置方式
- 引入依赖:使用gateway依赖时,不能同时引入spring-boot-starter-web依赖。gateway配合nacos使用别名进行路由,需要使用负载均衡(而nacos依赖不包含),因此要单独引入loadbalancer依赖
xml
<!--gateway-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
- application.yml配置
yml
spring:
cloud:
gateway:
discovery:
locator:
# 从服务注册中心根据别名来进行路由
enabled: true
routes:
# 路由Id,自定义,唯一即可
- id: nacos-provider-test
# 成功匹配后,要转换成的路由地址(配合服务注册中心使用别名),需要负载均衡依赖
uri: lb://nacos-provider
# 成功匹配后,要转换成的路由地址(不配合服务注册中心)
#uri: http://localhost:8001
# 断言
predicates:
# 路径匹配的进行路由
- Path=/**
代码方式
java
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator myRouteLocator(RouteLocatorBuilder builder) {
RouteLocatorBuilder.Builder routes = builder.routes();
routes.route("nacos-provider-test", r -> r.path("/**").uri("lb://nacos-provider"));
return routes.build();
}
}
路由配置
路由是由ID、URI、一系列的断言和过滤器组成的。断言可以匹配请求中的所有内容,如果请求与断言相匹配则进行路由。URI是进行路由时,要转换成的路由地址。在满足断言之后,过滤器可以修改向URI发送的请求和返回的响应。
断言
gateway本身内置许多断言(RoutePredicateFactory接口的实现类),多个断言可以组合使用。
当一个请求可以满足多个路由的断言时,会按定义的顺序找第一个满足断言的路由。
内置断言
内置断言中用到的时间格式可以用代码ZonedDateTime.now()
获取,也可以指定时间区域ZonedDateTime.now(ZoneId.of("Asia/Shanghai"))
。
常用内置断言
- Path
- 请求满足路径正则表达式则匹配
- 如:Path=/product-serv/segment,/server-b/**
- Method
- 请求满足指定请求方式则匹配
- 如:Method=GET,POST
- Cookie
- 请求cookie中存在指定key且value满足正则表达式则匹配
- 如:Cookie=key, valueReg
- Header
- 请求头中存在指定key且value满足正则表达式则匹配
- 如:Header=X-Request-Id, \d+
- Query
- 请求带有指定参数且value满足正则表达式则匹配
- 如:Query=name, fly
- RemoteAddr
- 请求的ip在指定ip/mask内则匹配
- 如:RemoteAddr=192.168.1.0/24
- Host
- 请求的host满足正则表达式则匹配
- 如:Host=localhost:8080,localhost:8081
- After
- 请求时间在指定时间之后则匹配,可用于在未来指定时间上线服务
- 如:After=2024-01-01T23:59:59.123+08:00[Asia/Shanghai]
- Before
- 请求时间在指定时间之前则匹配,可用于服务在指定时间内可访问
- 如:Before=2024-01-01T23:59:59.123+08:00[Asia/Shanghai]
- Between
- 请求时间在指定时间之间则匹配,可用于服务在指定时间内可访问
- 如:Between=2024-01-01T23:59:59.123+08:00[Asia/Shanghai], 2024-01-02T23:59:59.123+08:00[Asia/Shanghai]
自定义断言
- 创建类并@Component注入:类名要求是XxxRoutePredicateFactory(配置文件中使用断言时,断言名为Xxx)
java
@Component
public class CustomRoutePredicateFactory
- 创建静态内部类:用于接收参数,因此要有属性值和对应的getter和setter
java
@Getter
@Setter
public static class Config {
private String key;
private String value;
}
- 继承抽象类:继承断言工厂类AbstractRoutePredicateFactory并确定泛型为内部类
java
@Component
public class CustomRoutePredicateFactory extends AbstractRoutePredicateFactory<CustomRoutePredicateFactory.Config>
- 构造方法
java
public CustomRoutePredicateFactory() {
super(Config.class);
}
- 重写读配置文件方法:方法读取配置文件的参数值,赋值到内部类中的属性上(顺序必须与yml文件中的配置顺序对应)
java
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("key", "value");
}
- 重写apply方法:返回true路由成功,返回false返回404(serverWebExchange可以获取很多内容)
java
@Override
public Predicate<ServerWebExchange> apply(Config config) {
return new Predicate<ServerWebExchange>() {
@Override
public boolean test(ServerWebExchange serverWebExchange) {
List<String> strings = serverWebExchange.getRequest().getHeaders().get(config.key);
if (strings==null || strings.isEmpty())
return false;
return config.value.equals(strings.get(0));
}
};
}
- yml文件中配置断言
yml
Custom=test, a
过滤器
过滤器分为局部过滤器和全局过滤器,局部过滤器仅在配置的路由上起效,而全局过滤器对所有的路由都起效。
内置局部过滤器
常用内置过滤器
-
StripPrefix
- 转换成路由之前,去掉URL中前面几节
- 如:StripPrefix=1
-
PrefixPath
- 给请求路径path添加前缀
- 如:PrefixPath=/nacos
-
AddRequestParameter
- 添加请求参数
- 如:AddRequestParameter=name,test
-
RemoveRequestParameter
- 删除请求参数
- 如:RemoveRequestParameter=name
-
AddRequestHeader
- 在请求头上添加参数
- 如:AddRequestHeader=key,value
-
SetRequestHeader
- 修改请求头上指定参数的值,参数不存在时创建
- 如:SetRequestHeader=myHeader, test
-
RemoveRequestHeader
- 删除请求头上的指定参数
- 如:RemoveRequestHeader=MyHeader
-
AddResponseHeader
- 在响应头上添加参数
- 如:AddRequestHeader=key,value
-
SetResponseHeader
- 修改响应头上指定参数的值,参数不存在时创建
- 如:SetResponseHeader=addHeader, test
-
RewriteResponseHeader
- 修改响应头上指定参数的值,第一个参数是key,第二个参数是正则表达式匹配修改前的值,第三个参数是修改后的值
- 如:RewriteResponseHeader=addHeader,test1,test
-
RemoveResponseHeader
- 删除响应头上的指定参数
- 如:RemoveResponseHeader=addHeader
-
SetStatus
- 设置返回的响应码
- 如:SetStatus=500
-
RedirectTo
- 重定向,两个参数分别是重定向300系列状态码和URL
- 如:RedirectTo=302, https://www.baidu.com
-
RewritePath
- 重写请求路径
- 如:RewritePath=/test1/?(?.*), /nacos/${segment}
自定义局部过滤器
- 创建类并@Component注入:类名要求是XxxGatewayFilterFactory(配置文件中使用过滤器时,过滤器名为Xxx)
java
@Component
public class CustomGatewayFilterFactory
- 创建静态内部类:用于接收参数,因此要有属性值和对应的getter和setter
java
@Getter
@Setter
public static class Config {
private String key;
private String value;
}
- 继承抽象类:继承过滤器工厂类AbstractGatewayFilterFactory并确定泛型为内部类
java
@Component
public class CustomGatewayFilterFactory extends AbstractGatewayFilterFactory<CustomGatewayFilterFactory.Config>
- 构造方法
java
public CustomRoutePredicateFactory() {
super(Config.class);
}
- 重写读配置文件方法:方法读取配置文件的参数值,赋值到内部类中的属性上(顺序必须与yml文件中的配置顺序对应)
java
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("key", "value");
}
- 重写apply方法:可以在chain.filter(exchange).then之前操作request,之后操作response(serverWebExchange可以获取很多内容)
java
@Override
public GatewayFilter apply(Config config) {
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// pre操作
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
// 异步post操作
}));
}
};
}
- yml文件中配置断言
yml
Custom=test, a
自定义全局过滤器
- 创建GlobalFilter、Ordered接口实现类并@Component注入
java
@Component
public class CustomGlobalFilter implements GlobalFilter, Ordered
- 重写getOrder方法:方法返回的值越小,过滤器的优先级越高
java
@Override
public int getOrder() {
return 0;
}
- 重写filter方法
java
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// pre操作
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
// 异步post操作
}));
}