Spring Cloud Gateway
SpringCloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。SpringCloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Zuul,在Spring Cloud 2.0以上版本中,没有对新版本的Zuul 2.0以上最新高性能版本进行集成,仍然还是使用的Zuul 2.0之前的非Reactor模式的老版本。而为了提升网关的性能,SpringCloud Gateway是基于WebFlux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty。Spring Cloud Gateway 的目标,不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控/指标,和限流。
特性
- 动态路由:能够匹配任何请求属性
- 可以对路由指定 Predicate(断言)和 Filter(过滤器)
- 集成 Hystrix 的断路器功能
- 集成 Spring Cloud 服务发现功能
- 请求限流功能
- 支持重新路径
Gateway & Zuul
- Zuul 1.x ,是一个基于阻塞I/O的API Gateway。
- Zuul 1.x 基于 Servlet 2.5 使用阻寒架构它不支持任何长连接 (如 WebSocket ) Zuul 的设计模式和 Nginx 较像,每次 l/О 操作都是从工作线程中选择一个执行,请求线程被阻塞到工作线程完成,但是差别是 Nginx 用 C++ 实现,Zuul 用Java 实现,而JVM本身—次加载较慢的情况,使得Zuul的性能相对较差。
- Zuul 2.x理念更先进,想基于Netty非阻塞和支持长连接,但SpringCloud目前还没有整合。Zuul 2.x的性能较Zuul 1.x有较。在性能方面,根据官方提供的基准测试,Spring Cloud Gateway的RPS(每秒请求数)是Zuul的1.6倍。
- Spring Cloud Gateway 建立在 Spring Framework 5、Project Reactor 和 Spring Boot 2 之上,使用非阻塞 API。
- Spring Cloud Gateway 还支持 WebSocket,并且与 Spring 紧密集成拥有更好的开发体验。
Router 路由
路由时构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true
则匹配该路由。
Predicate 断言
参考的时 Java8 的 java.util.function.Predicate
,开发人员可以匹配 HTTP 请求中的所有内容(请求头或请求参数),如果请求与断言相匹配则进行路由。
Filter 过滤
指 Spring 框架中 Gateway Filter 的实例,使用过滤器,可以在请求被路由前或者路由之后对请求进行修改。
搭建
依赖坐标
web支持的话需要导入spring-boot-starter-webflux 而不是 web
<!-- spring cloud gateway -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
配置
路由由两种配置方式
yml配置
server:
port: 9527
spring:
application:
name: gateway9527
cloud:
gateway:
routes:
# 路由的ID,没有固定规则但要求唯一,建议配合服务名
- id: payment_router0
# 匹配后提供服务的路由地址
uri: http://localhost:8001
#断言,路径相匹配的进行路由
predicates:
- Path=/payment/get/**
- id: payment_router1
uri: http://localhost:8001
predicates:
- Path=/payment/port/**
eureka:
instance:
hostname: gateway-server
client:
service-url:
fetch-registry: true
register-with-eureka: true
defaultZone: http://localhost:7001/eureka,http://localhost:7002/eureka
注入RouteLocator的Bean
当访问 http://localhost:9527/guonei 时,映射 http://news.baidu.com/guonei
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator routeLocator(RouteLocatorBuilder routeLocatorBuilder) {
RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
//当访问 http://localhost:9527/guonei 时,映射 http://news.baidu.com/guonei
routes.route("router_test_0", r -> r.path("/guonei").uri("http://news.baidu.com/guonei"))
.route("router_test_1", r -> r.path("/guoji").uri("https://news.baidu.com/guoji"));
return routes.build();
}
}
启动类
@SpringBootApplication
@EnableEurekaClient
public class GatewayApplication9527 {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication9527.class, args);
}
}
动态路由
默认情况下 Gateway 会根据注册中心的服务列表,以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能。
配置
spring:
application:
name: gateway9527
cloud:
gateway:
discovery:
locator:
# 开启从注册中心动态创建的功能,利用微服务名进行路由
enabled: true
routes:
# 路由的ID,没有固定规则但要求唯一,建议配合服务名
- id: payment_router0
# 负载均衡,通过服务名进行访问
uri: lb://PROVIDER-PAYMENT
#断言,路径相匹配的进行路由
predicates:
- Path=/payment/**
Predicate 断言
Spring Cloud Gateway 将路由配置作为 Spring WebFlux Handler Mapping 基础架构的一部分。Spring Cloud Gateway 包括许多内置的 Router Predicate 工厂。所有这些 Predicate 都与 HTTP 请求的不同属性匹配。多个 Router Predicate 工厂可以进行组合。
Spring Cloud Gateway 创建
Router
对象时,使用RouterPredicateFactory
创建Predicate
对象,Predicate
对象可以赋值给Router
。Spring Cloud Gateway 包含许多内置的 Route Predicate Factories。所有这些谓词都匹配 HTTP 请求的不同属性。多种谓词工厂可以组合,并通过逻辑 and。
After Route Predicate
在指定时间后,才能够访问匹配的接口。
predicates:
- Path=/payment/**
- After=2021-04-19T12:30:15.222+08:00[Asia/Shanghai]
Before Route Predicate
在指定时间之前,才能够访问匹配的接口。
predicates:
- Path=/payment/**
- Before=2021-04-18T12:30:15.222+08:00[Asia/Shanghai]
Between Route Predicate
在指定时间之间,才能够访问匹配的接口。以
,
分割时间
predicates:
- Path=/payment/**
- Between=2021-04-18T12:30:15.222+08:00[Asia/Shanghai],2021-04-19T12:30:15.222+08:00[Asia/Shanghai],
Cookie Route Predicate
需要两个参数:Cookie name 和 正则表达式。路由规则会通过获取对应的 Cookie name 值和正则表达式去匹配,如果匹配上就会执行路由,如果没有匹配上则不执行。
需要带上username
的 Cookie,值为vip
。
predicates:
- Path=/payment/**
- After=2021-04-18T12:30:15.222+08:00[Asia/Shanghai]
# Cookie
- Cookie=username,vip
Header Route Predicate
需要两个参数:属性名称和正则表达式,这个属性值和正则表达式匹配则执行。
请求头要有X-Request-Id
属性,并且值为整数。
predicates:
- Path=/payment/**
- Header=X-Request-Id,\d+
Host Route Predicate
接收一组参数,一组匹配的域名列表,这个模板是一个 ant 分隔的模板,用
.
作为分隔符。它通过参数中的主机地址作为匹配规则。
只用xxx.localhost.com
的主机才可访问,或IP地址为198开头
predicates:
- Path=/payment/**
- Host=**.localhost.com,198.*.*.*
Method Route Predicate
匹配请求方法
predicates:
- Path=/payment/**
- Method=GET
Path Route Predicate
匹配路径
predicates:
- Path=/payment/**
Query Route Predicate
接收两个参数,请求参数名和正则表达式,参数名的值必须满足正则才可访问。
请求参数必须要有username
,值必须是正数
predicates:
- Path=/payment/**
- Query=username,\d+
更多自带谓语匹配请查询官网=
Filter 过滤
指的是 Spring 框架中 GatewayFilter 的实例,使用过滤器,可以在请求被路由前或者后对请求进行修改。路由过滤器可用于修改进入的 HTTP 请求和返回的 HTTP 响应,路由过滤器只能指定路由进行使用。Spring Cloud Gateway 内置了多种路由过滤器,他们都由 GatewayFilter 的工厂类来生产。
生命周期
pre
请求路由之前执行
post
请求路由之后执行
种类
# 过滤器
filters:
# 过滤器工厂会在匹配的请求头上加上一对请求头,名称为X-Request-Id值为1024
- AddRequestParameter=X-Request-Id,1024
GatewayFilter
GlobalFilter
自定义
需要实现两个接口
GlobalFilter
Ordered
@Component
@Slf4j
public class LogGatewayFilter implements GlobalFilter, Ordered {
/**
* 过滤
* @param exchange 交换器
* @param chain 调用链路
* @return 是否放行
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("============ LogGatewayFilter ============");
String username = exchange.getRequest().getQueryParams().getFirst("username");
if (StringUtil.isNullOrEmpty(username)) {
log.error("============ 非法用户");
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
//不通过
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
/**
* 优先执行顺序的权重
* @return 权重
*/
@Override
public int getOrder() {
return 0;
}
}