SpringCloud Gateway
简介
Spring Cloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。
Spring Cloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Netflix Zuul,其不仅提供统一的路由 方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控/指标,和限流。
概念
Route(路由):这是网关的基本构建块。它由一个 ID,一个目标 URI,一组断言和一组过滤器定义。如果断言为 真,则路由匹配。
Predicate(断言):这是一个 Java 8 的 Predicate。输入类型是一个 ServerWebExchange。我们可以使用它来匹 配来自 HTTP 请求的任何内容,例如 headers 或参数。
Filter(过滤器):这是org.springframework.cloud.gateway.filter.GatewayFilter的实例,我们可以使用它修改请 求和响应。
Gateway和Zuul的区别与联系
Zuul
目前zuul有两个版本:zuul1和zuul2,目前spring cloud只集成了zuul1。zuul2是Netflix在2018年5月推出,它最 大的特点就是支持异步调用 (zuul1仅支持同步) ,可惜springcloud暂时没有计划集成zuul2,而且还推出spring cloud gateway来替代zuul1。
本质上就是一个同步 Servlet,每来一个请求,zuul会专门分配一个线程去处理,然后转发到后端服务,后端再启 线程处理请求,后端处理时网关的线程会阻塞,当请求数量比较大时,很容易造成线程池被沾满而无法接受新的请求,Netflix 为此还专门研发了Hystrix熔断组件来解决慢服务耗尽资源问题。
Gateway
Spring Cloud Gateway构建于 Spring 5+,基于 Spring Boot 2.x 响应式的、非阻塞式的 API。同时,它支持 websockets,和 Spring 框架紧密集成,开发体验相对来说十分不错。由于zuul2没有被spring cloud所集成,所以 拿zuul1与spring cloud gateway做一些简单的比较。
以下是比较图:
依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
常用配置
spring:
cloud:
gateway:
discovery:
locator:
enabled: true #开启从注册中心动态创建路由
routes: # 路由数组[路由 就是指定当请求满足什么条件的时候转到哪个微服务]
- id: user-app # 当前路由的标识, 要求唯一
uri: lb://user-app #注册中心的配置
#uri: http://localhost:8081 #实际路径
#order: 1 # 路由的优先级,数字越小级别越高
predicates: # 断言(就是路由转发要满足的条件)
#- Path=/api/user/** # 当请求路径满足Path指定的规则时,才进行路由转发
#- After=2022-01-20T06:06:06+08:00[Asia/Shanghai] #这个时间以后生效
#- Cookie=username,mj #Cookie名必须为mj才能访问
#- Method=GET #只有GET方法能访问
#filters: # 过滤器,请求在传递过程中可以通过过滤器对其进行一定的修改
#- StripPrefix=2 # 转发之前去掉1层路径
http://localhost:10011/api/user/login
http://localhost:8083/login
过滤器
@Component
@EnableConfigurationProperties({FilterProperties.class, JwtProperties.class})
public class LoginFilter implements GlobalFilter, Ordered {
@Resource
private FilterProperties filterProperties;
@Resource
private JwtProperties jwtProperties;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
String path = request.getURI().getPath();
if (isAllowPath(path)) {
//放行
return chain.filter(exchange);
}
String token = request.getHeaders().getFirst("token");
if (StringUtils.isEmpty(token)) {
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return authError(response, ExceptionEnum.TOKEN_IS_EMPTY);
}
try {
JwtUtils.getUserInfo(jwtProperties.getPublicKey(), token);
} catch (Exception e) {
return authError(response, ExceptionEnum.TOKEN_IS_ERROR);
}
return chain.filter(exchange);
}
@Override public int getOrder() {
return 0;
}
public boolean isAllowPath(String path) {
System.out.println(path);
if (filterProperties.getAllowPaths().contains(path)) {
return true;
}
return false;
}
private Mono<Void> authError(ServerHttpResponse response, ExceptionEnum exceptionEnum) {
Response<Object> fail = ResponseApi.setFail(exceptionEnum.message(), exceptionEnum.value());
DataBuffer dataBuffer = response.bufferFactory().wrap(JSON.toJSONBytes(fail));
return response.writeWith(Flux.just(dataBuffer));
}
}