八、网关Gateway
SpringCloud推出的新一代网关Gateway.....
一、Gateway介绍
① Getway 简介
由于Netflix
在zull
、zull2
的推出出现问题,SpringCloud
推出了自己的网关GeteWay
。
Gateway
是Spring Cloud
的一个全新项目,基于Spring 5.0
+Spring Boot 2.0
和Project Reactor
等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的API
路由管理方式。
Gateway
作为SpringCloud
生态系统中的网关,目标是替代Zuul
,在Spring Cloud 2.0
以上版本中,没有对新版本的Zuul 2.0
以上最新高性能版本进行集成,仍然还是使用的Zuul 1.x
非Reactor
模式的老版本。而为了提升网关的性能,Gateway
是基于WebFlux
框架实现的,而WebFlux
框架底层则使用了高性能的Reactor
模式通信框架Netty
。
Gateway
的目标提供统一的路由方式且基于Filter
链的方式提供了网关基本的功能,例如:安全、监控/指标、和限流。
② Gateway 作用
- 反向代理
- 鉴权
- 流量控制
- 熔断
- 日志监控
③ Gateway 三大核心概念
Route
(路由)
路由是构建网关的基本模块,它由ID
,目标URI
,一系列的断言和过滤器组成,如果断言为true
则匹配该路由。Predicate
(断言)
参考JAVA8
的java.util.function.Predicate
开发人员可以匹配HTTP
请求中的所有内容(例如请求头和请求参数),如果请求与断言相匹配则进行路由- Filter(过滤)
指的是Spring
框架中GatewayFilter
的实例,使用过滤器,可以在请求被路由前或之后对请求进行修改
web
请求通过一些匹配条件,定位到真正的服务节点,并在这个转发过程的前后,进行一些细化控制。
pridicate
就是我们的匹配条件;而filter
,就可以理解为一个无所不能的拦截器。有了这两个元素,再加上目标url
,就可以实现一个具体的路由了。
④ Gateway 流程
客户端向Spring Cloud Gateway
发出请求。然后在Gateway Handler Mapping
中找到与请求相匹配的路由,将其发送到GatewayWeb Handler
。
Handler
再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。
过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前( pre
)或之后(post
)执行业务逻辑。
Filter
在pre
类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等,在post
类型的过滤器中可以做响应内容、响应头的修改,日志的输出,流量监控等有着非常重要的作用。
核心逻辑:路由转发+执行过滤器链
二、Gateway的使用
2.1. 入门
① 新建一个项目cloud-gateway9527
,添加Gateway
的依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
② 我们不想暴露8001项目的端口,因此在9527做路由映射,有两种路由映射方式:
yml 配置
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名称进行路由
routes:
- id: payment_route # 路由的id,没有规定规则但要求唯一,建议配合服务名
#匹配后提供服务的路由地址
uri: http://localhost:8001
predicates:
- Path=/payment/discovery/** # 断言,路径相匹配的进行路由
编码
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
RouteLocatorBuilder.Builder routes = builder.routes();
routes.route("/payment_route2",
route -> route.path("/payment/discovery/**")
.uri("http://localhost:8001")
);
return routes.build();
}
}
③ 经测试,这两种方式均可行:
2.2 通过微服务名实现动态路由
默认情况下Gateway
会根据注册中心的服务列表,以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能。
需要注意的是uri
的协议为lb
,表示启用Gateway
的负载均衡功能。修改uri
即可:
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名称进行路由
routes:
- id: payment_route # 路由的id,没有规定规则但要求唯一,建议配合服务名
#lb://微服务名
uri: lb://CLOUD-PAYMENT-SERVICE
predicates:
- Path=/payment/discovery/** # 断言,路径相匹配的进行路由
2.3 Predicate的使用
Gateway
将路由匹配作为Spring WebFlux HandlerMapping
基础架构的一部分。Gateway
包括许多内置的Route Predicate
工厂,如下图。所有这些Predicate
都与HTTP
请求的不同属性匹配。多个Route Predicate
工厂可以进行组合。
Gateway
创建Route
对象时,使用Route Predicate Factory
创建Predicate
对象,Predicate
对象可以赋值给Route
。所有的 Route Predicate
都对应着HTTP
请求的不同属性。可以通过and
相互组合。
常用的Route Predicate Factory
:
① After/Before/Between
设置请求生效时间/失效时间,时间格式为java8
新出的java.time.ZonedDateTime
。
...
predicates:
- Path=/payment/discovery/** #路径相匹配的进行路由
- After=2020-04-17T20:28:54.492+08:00[Asia/Shanghai]
#- Before=2020-04-17T20:28:54.492+08:00[Asia/Shanghai]
#- Between=2020-04-16T20:28:54.492+08:00[Asia/Shanghai], 2020-04-17T20:28:54.492+08:00[Asia/Shanghai]
② Cookie/Header/HOST
Cookie Route Predicate
需要两个参数,一个是Cookie name
,一个是正则表达式。路由规则通过获取对应的Cookie name
值和正则表达式去匹配。
路由规则通过Header
去匹配。
路由规则通过Host
去匹配。
...
predicates:
- Path=/payment/discovery/**
- Cookie=username,zzyy
- Header=X-Request-Id, \d+ #请求头要有X-Request-Id属性,并且值为正数
- Host=**.ctj.com
其他Route Predicate Factory
参考官网。
总结:Predicate
就是为了实现一组匹配原则,让请求过来找到对应的Route
进行处理
2.4 Filter 的使用
路由过滤器可用于修改进入的HTTP
请求和返回的HTTP
响应,路由过滤器只能指定路由进行使用。
Gateway
内置了多种路由过滤器,他们都由GatewayFilter
的工厂 类来产生。其生命周期有两种:pre
(业务逻辑执行之前)和post
(业务逻辑执行之后)。种类有两种:GatewayFilter
和GlobalFilter
。
使用GatewayFilter
:
例:该AddRequestHeader
GatewayFilter
工厂需要name
和value
参数。它将X-Request-red:blue
标头添加到所有匹配请求的下游请求的标头中。
spring:
cloud:
gateway:
routes:
- id: add_request_header_route
uri: https://example.org
filters:
- AddRequestHeader=X-Request-red, blue
具体参考: 官网
自定义 GlobalFilter
作用:
- 全局日志记录
- 统一网关鉴权,可以结合
Spring Security
完成对用户的认证授权
用户校验实现代码:
@Component
@Slf4j
public class MyLogGatewayFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("******用户验证开始: " + new Date());
String uname = exchange.getRequest().getQueryParams().getFirst("uname");
if(uname == null) {
log.info("******非法用户******");
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
log.info("******用户验证成功******");
return chain.filter(exchange);
}
/**
* 加载过滤器的顺序,数据越小,优先级越高
* @return int
*/
@Override
public int getOrder() {
return 0;
}
}
访问http://localhost:9527/payment/discovery
日志打印,请求并且被拦截:
访问http://localhost:9527/payment/discovery?uname=a
日志打印,请求被放行:
更多推荐
所有评论(0)