文章目录
- 一、Gateway和Zuul的区别
- 二、Gateway的核心概念
- 三、小试牛刀
- 3.1、代码测试
- 3.2、关于Predicate
- 3.3、关于Filter
一、Gateway和Zuul的区别
Spring Cloud Gateway是在Spring生态系统之上构建的API网关服务,基于Spring 5,Spring Boot 2和 Project Reactor等技术。 Gateway 使用的Webflux中的reactor-netty响应式编程组件,底层使用了Netty通讯框架。Spring Cloud Gateway能干嘛呢?
Gateway是原zuul1.x版的替代。
Spring Cloud Gateway 与 Zuul的区别:
Zuul 1.x,是一个基于阻塞 I/ O 的 API Gateway,不支持任何长连接,Zuul 用 Java 实现,而 JVM 本身会有第一次加载较慢的情况,使得Zuul 的性能相对较差。
Zuul 2.x理念更先进,想基于Netty非阻塞和支持长连接,但SpringCloud目前还没有整合。 Zuul 2.x的性能较 Zuul 1.x 有较大提升。在性能方面,根据官方提供的基准测试, Spring Cloud Gateway 的 RPS(每秒请求数)是Zuul 的 1. 6 倍。
Spring Cloud Gateway 建立 在 Spring Framework 5、 Project Reactor 和 Spring Boot 2 之上, 使用非阻塞 API。 支持 WebSocket, 并且与Spring紧密集成拥有更好的开发体验。
二、Gateway的核心概念
Route(路由)
路由是构建网关的基本模块,由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由。
Predicate(断言)
参考Java8的java.util.function.Predicate,开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由。
Filter(过滤)
Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由之前或者之后对请求进行修改。
如图Gateway官网所示的工作流程:
①、客户端向 Spring Cloud Gateway 发出请求。然后在 Gateway Handler Mapping 中找到与请求相匹配的路由,将其发送到 Gateway Web Handler。
②、Handler 通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。
③、过滤器可能会在发送代理请求之前(“pre”)或之后(“post”)执行业务逻辑。
注: 在“pre”类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等,在“post”类型的过滤器中可以做响应内容、响应头的修改,日志的输出,流量监控等有着非常重要的作用。
三、小试牛刀
3.1、代码测试
使用SpringCloud Gateway测试之前,要开启Eureka Server,两个Eureka Client,请求调用过程如下:
新建model,添加pom依赖。GateWay属于SprinigCloud且有web依赖,在导入对应依赖时,要删除spring-boot-starter-web依赖
<!--gateway-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--一般基础配置类-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
添加application.yml文件:
server:
port: 9527
spring:
application:
name: cloud-gateway-service
cloud:
gateway:
routes:
- id: payment_route_one #路由的ID,没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8001
uri: lb://CLOUD-PAYMENT-SERVICE #匹配后提供服务的路由地址
filters: #过滤器,在路由成功后匹配执行
- AddRequestParameter=X_Test,777
predicates: # 断言,路径相匹配的进行路由
- Path=/payment/get/**
- id: payment_route_two
uri: lb://CLOUD-PAYMENT-SERVICE #uri的协议为lb,表示启用Gateway的负载均衡功能。
predicates:
- Path=/payment/show/**
- id: payment_route_three
uri: http://localhost:8001
predicates:
- Path=/payment/lb/**
discovery:
locator:
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
eureka:
instance:
hostname: cloud-gateway-service
client: #服务提供者provider注册进eureka服务列表内
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://eureka7001.com:7001/eureka
仔细分析一下配置中关于springcloud gateway的配置:
server:
port: 9527
spring:
application:
name: cloud-gateway-service
cloud:
gateway:
routes:
- id: payment_route_one #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: lb://CLOUD-PAYMENT-SERVICE #匹配后提供服务的路由地址
filters: #过滤器,在路由成功后匹配执行
- AddRequestParameter=X_Test,777
predicates: # 断言,路径相匹配的进行路由
- Path=/payment/get/**
routes 下面可以有多个路由配置,以id区分;每个路由有uri和predicates,表示当满足了predicates条件后,会成功路由到对应的uri;filters属性,增加了过滤器,表示在成功之后的路由中增加一个请求参数。
默认情况下Gateway会根据注册中心注册的服务列表,以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能uri的协议为lb,表示启用Gateway的负载均衡功能,lb://serviceName是spring cloud gateway在微服务中自动为我们创建的负载均衡uri。
启动类添加@EnableEurekaClient注解,启动Eureka Server和两个Eureka Client。
测试调用:
这个请求,从网关成功调用到8001。
Spring Cloud Gateway的路由配置,还支持以Bean的方式。
@Configuration
public class GateWayConfig {
@Bean
public RouteLocator getRouteLocator(RouteLocatorBuilder builder) {
RouteLocatorBuilder.Builder routes = builder.routes();
routes.route("payment_get_route", r -> r.path("/payment/two/get/**").uri("http://localhost:8002")).build();
return routes.build();
}
@Bean
public RouteLocator showRouteLocator(RouteLocatorBuilder builder) {
RouteLocatorBuilder.Builder routes = builder.routes();
routes.route("payment_show_route", r -> r.path("/payment/two/show/**").uri("http://localhost:8002")).build();
return routes.build();
}
}
3.2、关于Predicate
Spring Cloud Gateway 包括许多内置的Route Predicate工厂。所有这些Predicate都与HTTP请求的不同属性匹配。
Spring Cloud Gateway 创建 Route 对象时, 使用 RoutePredicateFactory 创建 Predicate 对象,Predicate 对象可以赋值给 Route。 Spring Cloud Gateway 包含许多内置的Route Predicate Factories。
3.3、关于Filter
路由过滤器可用于修改进入的HTTP请求和返回的HTTP响应,路由过滤器只能指定路由进行使用。
Spring Cloud Gateway 内置了多种路由过滤器,他们都由GatewayFilter的工厂类来产生。
Filter分为全局Filter和GatewayFilter ,其中GatewayFilter有近30种,常用的GatewayFilter在yml中针对单个route配置即可。
GlobalFilter,可以自定义类实现 GlobalFilter,Ordered 接口,
/**
* @Auther: songweichao
* @Date: 2023-04-18 17:58
* @Description:该全局过滤器,表示在所有的路由进来后,检查是否带某个参数,若携带,则通过,否则不通过。
*/
@Configuration
public class MyGateWayFilter implements GlobalFilter,Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
{
System.out.println("现在时间:"+new Date()+"\t 执行了自定义的全局过滤器: "+"MyGateWayFilter");
String uname = exchange.getRequest().getQueryParams().getFirst("cookie");
if (uname == null) {
System.out.println("cookie为null,拒绝请求");
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder()
{
return 0;
}
}
控制台打印
现在时间:Tue May 09 14:44:21 CST 2023 执行了自定义的全局过滤器: MyGateWayFilter
现在时间:Tue May 09 14:44:47 CST 2023 执行了自定义的全局过滤器: MyGateWayFilter
cookie为null,拒绝请求
这两部分可参考官网Spring Cloud Gateway,配合具体业务使用。