文章目录
1: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 1.x非Reactor模式的者版本。而为了提升网关的性能,SpringCloud Gateway是基于WebFlux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty.
-
Spring Cloud Gateway的目标提供统一的路由方式且基于Filter 链的方式提供了网关基本的功能,例如:安全,监控/指标,和限流。
-
微服务架构中网关的位置图
-
Gateway模型:WebFlux
传统的Web框架,比如说: struts2, springmvc等都是基于Servlet API与Servlet容器基础之上运行的。但是在Servlet3.1之后有了异步非阻塞的支持。而WebFlux是一个典型非阻塞异步的框架, 它的核心是基于Reactor的相关API实现的。相对于传统的web框架来说,它可以运行在诸如Netty, Undertow及支持Servlet3.1的容器 上。非阻塞式+函数式编程(Spring5必须让你使用java8)
2:Spring Cloud Gateway的特性
- 基于Spring Framework 5, Project Reactor和Spring Boot 2.0进行构建;
- 动态路由:能够匹配任何请求属性;
- 可以对路由指定Predicate (断言)和Filter (过滤器) ;
- 集成Hystrix的断路器功能;
- 集成Spring Cloud服务发现功能;
- 易于编写的Predicate (断言)和Filter (过滤器)
- 请求限流功能;
- 支持路径重写。
3:Gateway三大核心概念
Route(路由):路由是构建网关的基本模块,它由ID,目标URI, 一系列的断言和过滤器组成,如果断言为true则匹配该路由
Predicate(断言):开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由
Filter(过滤):指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改。
如下图所示工作流程
web请求,通过一些匹配条件,定位到真正的服务节点。并在这个转发过程的前后,进行一些精细化控制。predicate就是我们的匹配条件;而filter, 就可以理解为一个无所不能的拦截器。有了这两个元素,再加上目标uri,就可以实现一个具体的路由了
4:Gateway工作流程
核心逻辑:路由转发+执行过滤器链
工作步骤:
1:客户端向Spring Cloud Gateway发出请求。然后在Gateway Handler Mapping中找到与请求相匹配的路由,将其发送到GatewayWeb Handler。
2:Handler再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前( “pre” )或之后( “post” )执行业务逻辑。
Filter在"pre"类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等,在"post"类型的过滤器中可以做响应内容、响应头的修改,日志的输出,流量监控等有着非常重要的作用。
5:Gateway搭建路由网关
第一步:配置pom.xml
<!-- gateway -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- eureka client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
第二步:配置application.yml
server:
port: 9527
spring:
application:
name: cloud-getway
cloud:
gateway:
routes: # 路由器的id,没有固定规则,但要求唯一,建议配合服务名
- id: payment_routh3
uri: http://cloud-provider-hystrix-payment# 匹配后提供服务的路由地址
predicates:
- Path=/payment/circuit/** # 断言,路径相匹配的进行路由
eureka:
instance:
hostname: cloud-gateway-service
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:7001/eureka
第三步:测试
@SpringBootApplication
@EnableEurekaClient
public class GatewayMain9527 {
public static void main(String[] args) {
SpringApplication.run(GatewayMain9527.class, args);
}
}
6:Gateway配置路由的两种方式
第一种:在配置文件yml中配置
server:
port: 9527
spring:
application:
name: cloud-getway
cloud:
gateway:
routes:
# payment_route # 路由器的id,没有固定规则,但要求唯一,建议配合服务名
- id: payment_routh
# 匹配后提供服务的路由地址
# uri: http://localhost:8001
uri: lb://CLOUD-PAYMENT-SERVICE
# 断言,路径相匹配的进行路由
predicates:
- Path=/payment/get/**
第二种:代码中注入RouteLocator的Bean
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator routes(RouteLocatorBuilder builder){
RouteLocatorBuilder.Builder routes = builder.routes();
routes.route("path_route", r ->
r.path("/guonei")
.uri("http://news.baidu.com/guonei"));
return routes.build();
}
}
7:Gateway配置动态路由
- 默认情况下Gateway会根据注册中心注册的服务列表,以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能
修改application.yml配置文件,如下
discovery:
locator:
# 开启从注册中心动态创建路由的功能,利用微服务名进行路由
enabled: true
uri: lb://CLOUD-PAYMENT-SERVICE
server:
port: 9527
spring:
application:
name: cloud-getway
cloud:
gateway:
discovery:
locator:
# 开启从注册中心动态创建路由的功能,利用微服务名进行路由
enabled: true
routes:
# payment_route # 路由器的id,没有固定规则,但要求唯一,建议配合服务名
- id: payment_routh
# 匹配后提供服务的路由地址
# uri: http://localhost:8001
uri: lb://CLOUD-PAYMENT-SERVICE
# 断言,路径相匹配的进行路由
predicates:
- Path=/payment/get/**
# payment_route2 # 路由器的id,没有固定规则,但要求唯一,建议配合服务名
- id: payment_routh2
# 匹配后提供服务的路由地址
# uri: http://localhost:8001
uri: lb://CLOUD-PAYMENT-SERVICE
# 断言,路径相匹配的进行路由
predicates:
- Path=/payment/lb/**
- id: payment_routh3
uri: lb://cloud-provider-hystrix-payment
predicates:
- Path=/payment/circuit/**
eureka:
instance:
hostname: cloud-gateway-service
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:7001/eureka
测试
8:Gateway的Predicate
springcloud组件gateway断言(Predicate)
9:Gateway的自定义过滤器
- 在Spring-Cloud-Gateway之请求处理流程中最终网关是将请求交给过滤器链表进行处理。
核心接口:GatewayFilter,GlobalFilter,GatewayFilterChain。
- Spring Cloud Gateway 的 Filter 的生命周期有两个:“pre” 和 “post”。
“pre”和 “post” 分别会在请求被执行前调用和被执行后调用,和 Zuul Filter 或 Spring Interceptor 中相关生命周期类似,但在形式上有些不一样。
Zuul 的 Filter 是通过filterType()方法来指定,一个 Filter 只能对应一种类型,要么是 “pre” 要么是“post”。Spring Interceptor 是通过重写HandlerInterceptor中的三个方法来实现的。而 Spring Cloud Gateway 基于 Project Reactor 和 WebFlux,采用响应式编程风格,打开它的 Filter 的接口GatewayFilter你会发现它只有一个方法filter。
-
实现自己的过滤器我们其实可以去查看Spring Cloud Gateway自带过滤器源码是如何实现的,
-
自定义过滤器比它自带的好用
//此功能是看是否地址有uname的参数
@Component
@Slf4j
public class MyLogGatewayFilter implements GatewayFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String uname=exchange.getRequest().getQueryParams().getFirst("uname");
if (uname==null){
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
/*
*过滤器存在优先级,order越大,优先级越低
*/
@Override
public int getOrder() {
return 0;
}
}