Spring cloud gateway是spring官方基于Spring 5.0、Spring Boot2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供简单、有效和统一的API路由管理方式,Spring Cloud Gateway作为Spring Cloud生态系统中的网关,目标是替代Netflix Zuul,其不仅提供统一的路由方式,并且还基于Filer链的方式提供了网关基本的功能,例如:安全、监控/埋点、限流等。
由于Zuul 1.x版本的停止维护,Spring Cloud Gateway是替代Zuul的最佳方案。
运维人员: 我们之前通过Ngnix使用路由转发,需要手动的维护转发的实例和路由规则,如增加机器,减少机器都需要人员手动的在Ngnix的配置文件中手动修改。但我们服务的实例比较多后,很明显是很不方便的。
开发人员: 我们针对每一个服务的端口都有一套校验的规则。但是在微服务中,我们拆分应用为多个服务,占据多个端口,如果没有一套统一的管理,是很麻烦的事情。
Zuul 1.x:构建于 Servlet 2.5,兼容 3.x,使用的是阻塞式的 API,不支持长连接.
Gateway: 构建于 Spring 5+,基于 Spring Boot 2.x 响应式的、非阻塞式的 API。支持 websockets,和Spring 框架紧密集成。底层使用netty模型,性能极高。
服务网关的核心思想是:路由转发和执行过滤链
,而SpringCloudGateWay中主要有三个核心的概念
路由是网关最基础的部分,路由信息有一个ID、一个目的URL、一组断言和一组Filter组成。如果断言路由为真,则说明请求的URL和配置匹配
Spring Cloud Gateway中的断言函数输入类型是Spring5.0框架中的ServerWebExchange。Spring Cloud Gateway中的断言函数允许开发者去定义匹配来自于http request中的任何信息。目前SpringCloud Gateway支持多种方式,常见如:Path、Query、Method、Header等。
我们经常的使用的是Path来对路径进行匹配,但我们还可以使用例如After:xxxTime,代表xxx时间后该路径才能生效.
一个标准的Spring webFilter。Spring cloud gateway中的filter分为两种类型的Filter,分别是Gateway Filter和Global Filter。过滤器Filter将会对请求和响应进行修改处理.
如上图所示,Spring cloudGateway发出请求。然后再由Gateway Handler Mapping中找到与请求相匹配的路由,将其发送到Gateway web handler。Handler再通过指定的过滤器链将请求发送到我们实际的服务执行业务逻辑,然后返回。
导入依赖
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-gatewayartifactId>
dependency>
cloud:
gateway:
routes:
- id: route1 #路由Id,没有固定要求但要求唯一
uri: http://localhost:8081 #匹配提供服务的路由地址
predicates:
Path=/payment/get/** #断言,路径相匹配后提供路由
- id: route2 #路由Id,没有固定要求但要求唯一
uri: http://localhost:8081 #匹配提供服务的路由地址
predicates:
Path=/payment/do/** #断言,路径相匹配后提供路由
很明显,这里两个方法进行了路由的映射。我们之前访问的是http://localhost:8081/payment/get/1
l而现在我们访问的是http://localhost:9002/payment/get/1
l
类似于yml配置,我们将localhost:9002/baidu
映射到了www.baidu.com
/**
1. 通过编码配置Gateway路由
*/
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator getCustomRouteLocator(RouteLocatorBuilder builder) {
RouteLocatorBuilder.Builder routes = builder.routes();
routes.route("route3",
r -> r.path("/baidu")
.uri("https://www.baidu.com/"))
.build();
return routes.build();
}
}
当之前的8081
服务是集群的时候(如有8081
、8082
构成集群)时,我们则需要开启动态路由.
lb:服务名
进行调用cloud:
gateway:
routes:
- id: route1 #路由Id,没有固定要求但要求唯一
#uri: http://localhost:8081 #匹配提供服务的路由地址
uri: lb://cloud-payment-service
predicates:
Path=/payment/get/** #断言,路径相匹配后提供路由
- id: route2 #路由Id,没有固定要求但要求唯一
uri: http://localhost:8081 #匹配提供服务的路由地址
predicates:
Path=/payment/do/** #断言,路径相匹配后提供路由
discovery:
locator:
enabled: true #开启从注册中心创建动态路由的功能,利用微服务名进行路由
实现GlobalFilter
、Ordered
接口并重写方法.
@Component
@Slf4j
public class MyGateWayFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String name = exchange.getRequest().getQueryParams().getFirst("name");
if (name == null) {
log.info("用户名为空");
exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
//优先级
@Override
public int getOrder() {
return 0;
}
}
很明显,我们自定义的filter访问时需要带上不为空的name参数.
相关源码:https://github.com/wantao666/SpringCloud2020