介绍
Cloud全家桶中有个很重要的组件就是网关,在1.x版本中都是采用的Zuul网关;但在2.x版本中,zuul的升级一直跳票,SpringCloud最后自己研发了一个网关替代Zuul,那就是SpringCloud Gateway
Gateway是在Spring生态系统之上构建的API网关服务
Gateway旨在提供一种简单而有效的方式来对API进行路由,以及提供一些强大的过滤器功能,例如:熔断、限流、重试等
Gateway是基于WebFlux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty
Gateway的目标提供统一的路由方式且基于 Filter链的方式提供了网关基本的功能,例如:安全,监控/指标,和限流。
作用
方向代理
鉴权
流量控制
熔断
日志监控
...
非阻塞异步模型
Gateway是基于异步非阻塞模型上进行开发的,性能方面不需要担心,是基于WebFlux框架实现的,WebFlux是一个典型非阻塞异步的框架,它的核心是基于Reactor的相关API实现的。相对于传统的web框架来说,它可以运行在诸如Netty,Undertow及支持Servlet3.1的容器上。非阻塞式+函数式编程(Spring 5必须让你使用Java 8)。
Spring WebFlux是Spring 5.0 引入的新的响应式框架,区别于Spring MVC,它不需要依赖Servlet APl,它是完全异步非阻塞的,并且基于Reactor来实现响应式流规范。
特性
基于Spring Framework 5,Project Reactor和Spring Boot 2.0进行构建;
动态路由:能够匹配任何请求属性;
可以对路由指定Predicate (断言)和Filter(过滤器);
集成Hystrix的断路器功能;
集成Spring Cloud 服务发现功能;
易于编写的Predicate (断言)和Filter(过滤器);
请求限流功能;
支持路径重写。
工作流程
Route(路由) - 路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如断言为true则匹配该路由;
Predicate(断言) - 参考的是Java8的java.util.function.Predicate,开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由;
Filter(过滤) - 指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改。
web请求,通过一些匹配条件,定位到真正的服务节点。并在这个转发过程的前后,进行一些精细化控制。predicate就是我们的匹配条件;而fliter,就可以理解为一个无所不能的拦截器。有了这两个元素,再加上目标uri,就可以实现一个具体的路由了
客户端向Spring Cloud Gateway发出请求。然后在Gateway Handler Mapping 中找到与请求相匹配的路由,将其发送到GatewayWeb Handler。
Handler再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。
过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前(“pre”)或之后(“post")执行业务逻辑。
Filter在“pre”类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等,在“post”类型的过滤器中可以做响应内容、响应头的修改,日志的输出,流量监控等有着非常重要的作用。
核心逻辑:路由转发 + 执行过滤器链。
入门使用
依赖
-
<!--gateway-->
-
<dependency>
-
<groupId>org.springframework.cloud
</groupId>
-
<artifactId>spring-cloud-starter-gateway
</artifactId>
-
</dependency>
YML
-
server:
-
port: 9127
-
-
spring:
-
application:
-
name: cloud-gateway
-
#############################网关配置###########################
-
cloud:
-
gateway:
-
routes:
-
- id: payment_routh #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
-
uri: http://localhost:8001 #匹配后提供服务的路由地址
-
#uri: lb://cloud-payment-service #匹配后提供服务的路由地址
-
predicates:
-
- Path=/payment/get/** # 断言,路径相匹配的进行路由
-
-
- id: payment_routh2 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
-
uri: http://localhost:8001 #匹配后提供服务的路由地址
-
#uri: lb://cloud-payment-service #匹配后提供服务的路由地址
-
predicates:
-
- Path=/payment/lb/** # 断言,路径相匹配的进行路由
-
####################################################################
添加网关后,直接访问网关所在地址会路由到具体服务
配置路由的两种方式
YML配置文件配置路由
-
spring:
-
application:
-
name: cloud-gateway-gateway
-
cloud:
-
gateway:
-
routes:
-
# 路由的ID,没有固定规则,但要求唯一,建议配合服务名
-
- id: payment_routh
-
# 匹配后提供服务的路由地址
-
uri: http://localhost:8001
-
# 断言,路径相匹配的进行路由
-
predicates:
-
- Path=/payment/get/**
根据指定的路径,进行转发
通过配置类来配置路由
-
@Configuration
-
public
class
GateWayConfig {
-
-
@Bean
-
public RouteLocator
customRouteLocator
(RouteLocatorBuilder routeLocatorBuilder){
-
RouteLocatorBuilder.
Builder
routes
= routeLocatorBuilder.routes();
-
-
routes.route(
"path_route_frx01",
-
r -> r.path(
"/guonei")
-
.uri(
"http://xxx/xxx")).build();
-
return routes.build();
-
}
-
}
代码中注入RouteLocator的Bean
GateWay配置动态路由
默认情况下Gateway会根据注册中心注册的服务列表,以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能(不写死一个地址)。
-
server:
-
port: 9127
-
-
spring:
-
application:
-
name: cloud-gateway
-
#############################网关配置###########################
-
cloud:
-
gateway:
-
discovery:
-
locator:
-
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
-
routes:
-
- id: payment_routh #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
-
#uri: http://localhost:8001 #匹配后提供服务的路由地址
-
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
-
predicates:
-
- Path=/payment/get/** # 断言,路径相匹配的进行路由
-
-
- id: payment_routh2 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
-
#uri: http://localhost:8001 #匹配后提供服务的路由地址
-
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
-
predicates:
-
- Path=/payment/lb/** # 断言,路径相匹配的进行路由
-
####################################################################
需要注意的是uri的协议为lb,表示启用Gateway的负载均衡功能。
lb://serviceName是spring cloud gateway在微服务中自动为我们创建的负载均衡uri。
常用的Predicate
Spring Cloud Gateway将路由匹配作为Spring WebFlux HandlerMapping基础架构的一部分。Spring Cloud Gateway包括许多内置的Route Predicate工厂。所有这些Predicate都与HTTP请求的不同属性匹配。多个RoutePredicate工厂可以进行组合。
常用的Route Predicate Factory
The After Route Predicate Factory
-
spring:
-
cloud:
-
gateway:
-
routes:
-
- id: after_route
-
uri: https://example.org
-
predicates:
-
# 这个时间后才能起效
-
- After=2023-01-20T17:42:47.789-07:00[America/Denver]
可以通过下述方法获得上述格式的时间戳字符串
-
import java.time.ZonedDateTime;
-
-
-
public
class
T2
-
{
-
public
static
void
main
(String[] args)
-
{
-
ZonedDateTime
zbj
= ZonedDateTime.now();
// 默认时区
-
System.out.println(zbj);
-
//2022-08-20T21:02:40.570+08:00[Asia/Shanghai]
-
-
}
-
}
The Before Route Predicate Factory
The Between Route Predicate Factory
-
spring:
-
cloud:
-
gateway:
-
routes:
-
- id: between_route
-
uri: https://example.org
-
# 两个时间点之间
-
predicates:
-
- Between=2023-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]
The Cookie Route Predicate Factory
-
spring:
-
cloud:
-
gateway:
-
routes:
-
- id: cookie_route
-
uri: http://localhost:8001
-
predicates:
-
- Cookie=chocolate, ch.p
-
# 该命令相当于发get请求,且没带cookie
-
curl http://localhost:9127/payment/lb
-
-
# 带cookie的
-
curl http://localhost:9127/payment/lb --cookie
"chocolate=chip"
The Header Route Predicate Factory
-
spring:
-
cloud:
-
gateway:
-
routes:
-
- id: header_route
-
uri: http://localhost:8001
-
predicates:
-
- Header=X-Request-Id, \d+
-
# 带指定请求头的参数的CURL命令
-
curl http://localhost:9527/payment/lb -H
"X-Request-Id:123"
The Host Route Predicate Factory
The Method Route Predicate Factory
The Path Route Predicate Factory
The Query Route Predicate Factory
The RemoteAddr Route Predicate Factory
The weight Route Predicate Factory
说白了,Predicate就是为了实现一组匹配规则,让请求过来找到对应的Route进行处理。
GateWay的Filter
路由过滤器可用于修改进入的HTTP请求和返回的HTTP响应,路由过滤器只能指定路由进行使用。Spring Cloud Gateway内置了多种路由过滤器,他们都由GatewayFilter的工厂类来产生。
生命周期
pre
post
种类
GatewayFilter - 有31种
常用的GatewayFilter:AddRequestParameter GatewayFilter
GlobalFilter - 有10种
主要接口
GlobalFilter
Ordered
作用
全局日志记录
统一网关鉴权
-
@Component
-
@Slf4j
-
public
class
MyLogGateWayFilter
implements
GlobalFilter, Ordered {
-
-
@Override
-
public Mono<Void>
filter
(ServerWebExchange exchange, GatewayFilterChain chain) {
-
log.info(
"***********come in MyLogGateWayFilter: "+
new
Date());
-
String
name
= exchange.getRequest().getQueryParams().getFirst(
"uname");
-
if(name==
null){
-
log.info(
"*******用户名为null,非法用户,o(╥﹏╥)o");
-
exchange.getResponse().setRawStatusCode(HttpStatus.HTTP_NOT_ACCEPTABLE);
-
return exchange.getResponse().setComplete();
-
}
-
return chain.filter(exchange);
-
}
-
-
@Override
-
public
int
getOrder
() {
-
return
0;
-
}
-
}
转载:https://blog.csdn.net/zhiwenganyong/article/details/128770409