1、介绍

强烈推荐,看官网文档

Spring Cloud Gateway

①简介

Cloud全家桶里有个重要组件:网关

SpringCloud Gateway基于WebFlux框架

WebFlux底层使用高性能的Reactor模式(异步非阻塞)通信框架Netty

②选择原因

  • 1.x版本采用Zuul网关

    但是在2.x版本中,zuul升级经常跳票,所以SpringCloud研发了SpringCloud Gateway代替1.x版本

    SpringCloud Gateway作为SpringCloud生态的网关,目标是替代Zuul,在SpringCloud2.0以上,没有对Zuul2.0以上进行集成,仍然使用Zuul1.x非Reactor模式的老版本。

  • SpringCloud Gateway属于Spring家族,整合更方便

  • 动态路由:能够匹配任何请求属性

  • 可以对路由指定Predicate(断言)和Filter(过滤器)

  • Zuul1.基于Servlet2.5使用阻塞架构,不支持任何长连接。Zuul2,SpringCloud没有整合。SpringCloud Gateway吸收Zuul2特点,使用非阻塞架构,支持长连接

③Zuul与Spring Cloud Gateway模型

一.Zuul模型(阻塞式)

使用Servlet2.5

当请求进入Container,会为其绑定一个线程,在并发不高的情况下模型还Ok。但是高并发情况下,线程数会飙升,而线程的资源代价很高贵(线程的上下文切换,内存消耗很大...)严重影响请求处理时间。

二.SpringCloud Gateway模型

在Servlet3.1之后有了异步非阻塞的支持

2、 三大概念

①路由

路由时构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为True,则匹配该路由。

②断言

参考Predicate

开发人员通过匹配HTTP请求中的内容(如请求头,请求参数),如果请求和断言匹配,进行路由

③过滤

在Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改。

3、SpringCloud Gateway工作流程

客户端向SpringCloud Gateway发请求,然后Gateway Handler Mapping中找到匹配的路由,将其发送到Gateway Web Handler中。

Handler再通过指定的过滤器链来将请求发送到我们的实际服务执行业务逻辑,然后返回。

过滤器之间用虚线分开,是因为过滤器可能会在发送请求之前(pre)和之后(post)执行逻辑

4、搭建

1.新建模块cloud-gateway-gateway9527

2.pom.xml:

<dependencies>
<!--gateway-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- 引用自己定义的api通用包,可以使用Payment支付Entity -->
<dependency>
<groupId>cn.zko0.cloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

3.yml:

将GetWay注册到Eureka上:

server:
port: 9527 spring:
application:
name: cloud-gateway
cloud:
gateway:
routes:
- id: payment_route # 路由的id,没有规定规则但要求唯一,建议配合服务名
#匹配后提供服务的路由地址
uri: http://localhost:8001
predicates:
- Path=/payment/get/** # 断言,路径相匹配的进行路由 - id: payment_route2
uri: http://localhost:8001
predicates:
- Path=/payment/lb/** #断言,路径相匹配的进行路由 eureka:
instance:
hostname: cloud-gateway-service
client:
fetch-registry: true
register-with-eureka: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka/

4.启动类:

@SpringBootApplication
@EnableEurekaClient
public class GatewayMain9527 {
public static void main(String[] args) {
SpringApplication.run(GatewayMain9527.class, args);
}
}

5.启动7001(注册中心),8001(Provider)与9527(Gatway)三个工程

6.服务调用测试:

8001调用测试:

9527调用测试:

5、两种配置方式

①配置文件

spring:
application:
name: cloud-gateway
cloud:
gateway:
routes:
- id: payment_route # 路由的id,没有规定规则但要求唯一,建议配合服务名
#匹配后提供服务的路由地址
uri: http://localhost:8001
predicates:
- Path=/payment/get/** # 断言,路径相匹配的进行路由 - id: payment_route2
uri: http://localhost:8001
predicates:
- Path=/payment/lb/** #断言,路径相匹配的进行路由

②代码注入RouteLocator的Bean

自拟一个需求:

通过Gateway路由到百度贴吧:

这里路由到百度知道存在错误,目前还没有找到原因,由于Gateway一般用于内网的转发,所以没有细究,主要学习Gateway的配置方式

@Configuration
public class GatwayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder){
RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
/*routes.route("path_route_angenin", //id
r -> r.path("/zhidao") //访问 http://localhost:9527/zhidao
.uri("https://zhidao.baidu.com/")); //就会转发到*/ routes.route("path_route_angenin2", //id
r -> r.path("/tieba") //访问 http://localhost:9527/tieba
.uri("https://tieba.baidu.com/index.html")); //就会转发到
return routes.build();
}
}

6、动态路由

①产生原因

在前面我们的配置都是写死了uri

8001和8002都是payment,如果后面我们对paymen服务进行扩容,出现了8003,8004等,那么这种方式就没有办法进行动态的调整了

②配置

通过微服务名实现动态路由

  1. 开启从注册中心动态创建路由的功能,利用微服务名称进行路由(默认false)

  2. 把写死的uri替换为服务名

    lb:是指路由的一种通信协议,它实现了负载均衡通信功能

总配置文件:

server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名称进行路由(默认false)
routes:
- id: payment_route # 路由的id,没有规定规则但要求唯一,建议配合服务名
#匹配后提供服务的路由地址
uri: lb://cloud-payment-service
predicates:
- Path=/payment/get/** # 断言,路径相匹配的进行路由 # - id: payment_route2
# uri: lb://cloud-payment-service
# predicates:
# - Path=/payment/xxxx #断言,路径相匹配的进行路由 eureka:
instance:
hostname: cloud-gateway-service
client:
fetch-registry: true
register-with-eureka: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka/

启动测试:

启动eureka注册中心,payment8001和8002,9827gateway

接口调用测试:成功

7、路由断言

之前我们的断言仅仅使用了uri的匹配

Springcloud Gateway还提供了很多其他断言判断条件:

SpringCloud断言文档

①The After Route Predicate Factory

时间级别还有:

  • The Before Route Predicate Factory
  • The Between Route Predicate Factory

配置:

测试类,获取当前的时间:

public class Test {
public static void main(String[] args) {
ZonedDateTime now = ZonedDateTime.now();
System.out.println(now);
}
}

通过上图我们能获得当前的时间

设置after断言判断,让当前时间在设置事件后,该路由才能生效

spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名称进行路由(默认false)
routes:
- id: payment_route # 路由的id,没有规定规则但要求唯一,建议配合服务名
#匹配后提供服务的路由地址
uri: lb://cloud-payment-service
predicates:
- Path=/payment/get/** # 断言,路径相匹配的进行路由
- After=2023-01-17T15:23:19.987+08:00[Asia/Shanghai]

重启测试:

由于时间未到after之后,所以路由未生效

②The Cookie Route Predicate Factory

下面的介绍来自官网,看官网就OK了

cookie 路由断言工厂采用两个参数,即 cookie 名称和正则表达式。 此谓词匹配具有给定名称且其值与正则表达式匹配的 Cookie。 以下示例配置 cookie 路由断言工厂:

配置:

spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名称进行路由(默认false)
routes:
- id: payment_route # 路由的id,没有规定规则但要求唯一,建议配合服务名
#匹配后提供服务的路由地址
uri: lb://cloud-payment-service
predicates:
- Path=/payment/get/** # 断言,路径相匹配的进行路由
#- After=2023-01-17T15:23:19.987+08:00[Asia/Shanghai]
- Cookie=username,fuckU

重启测试:

带Cookie调用,成功:

不带Cookie调用,或者Cookie错误,失败:

③The Header Route Predicate Factory

标头路由断言工厂采用两个参数,即标头名称和正则表达式。 此断言与具有给定名称的标头匹配,该标头的值与正则表达式匹配。 以下示例配置标头路由断言:

配置测试:

spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名称进行路由(默认false)
routes:
- id: payment_route # 路由的id,没有规定规则但要求唯一,建议配合服务名
#匹配后提供服务的路由地址
uri: lb://cloud-payment-service
predicates:
- Path=/payment/get/** # 断言,路径相匹配的进行路由
- Header=X-Request-Id, \d+
#- After=2023-01-17T15:23:19.987+08:00[Asia/Shanghai]
#- Cookie=username,fuckU

测试:

当Header中X-Request-Id的value为正整数,路由才能生效

④还有很多:略

参考Spring官网提供的文档即可:

SpringCloud断言文档

8、Gateway Filter

路由过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应。路由过滤器只能指定路由使用

①生命周期

  1. pre(前
  2. post(后

②种类

一.单一的Gateway Filter

用的比较少,略

二.全局过滤器

自定义全局GlobalFilter

新建config包,自定义全局过滤器:该过滤器能够通过检验请求参数是否包含username,来设置是否过滤请求:

@Slf4j
@Component
public class MyLogGateWayFilter implements GlobalFilter, Ordered { @Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("**************come in MyLogGatewayFilter{}",new Date());
String uname = exchange.getRequest().getQueryParams().getFirst("uname");
if (uname==null){
log.info("*****用户名为null,非法");
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
} @Override
//数字越小Filter的优先级越高
public int getOrder() {
return 0;
}
}

重启,测试:

请求附带参数,uname=1,成功

请求不附带参数,失败:

最新文章

  1. ABP理论学习之事件总线和领域事件
  2. linq to entity 获取项的集合总数
  3. PHP - __clone 对象克隆
  4. JS批量替换内容中关键词为超链接,避开已存在的链接和alt、title中的关键词
  5. Socket网络通信之数据传递
  6. Java中nextLine()与其他next(),nextInt(),nextFloat()的区别
  7. Do-Now—团队冲刺博客一(领航篇)
  8. SVN和Git的功能和区别,尚学堂SVN和Git学习视频资料免费下载
  9. March 07th, 2018 Week 10th Wednesday
  10. 关于mariad&amp;mysql部分
  11. unity3d-角色控制器续
  12. Easy ui DateBox 控件格式化显示操作
  13. Java--Inheritance constructor继承中的构造方法问题(二)
  14. VMwareWorkstation与Device/CredentialGuard不兼容
  15. Halcon标定
  16. [GO]简单的并发服务器
  17. iOS 数据库sqlite3.0操作--超简单--看我就够啦
  18. 【洛谷P1351】[NOIP2014]联合权值
  19. [CentOS7] gzip, bzip2, xz 压缩与解压缩
  20. 《深入理解JavaScript闭包和原型》笔记

热门文章

  1. Mysql5.6.44版本安装及基本配置
  2. CmakeLists简单使用总结
  3. 使用.NET7和C#11打造最快的序列化程序-以MemoryPack为例
  4. 【大数据面试】【框架】Shuffle优化、内存参数配置、Yarn工作机制、调度器使用
  5. 复杂mysql/多表查询
  6. 多线程/GIL全局锁
  7. Gepetto:使用chatGPT来对函数功能进行分析并重命名变量的IDA插件
  8. 痞子衡嵌入式:国内外串行NOR Flash厂商官网Cross Reference功能使用体验
  9. 微软出品自动化神器【Playwright+Java】系列(七) 之 元素的可操作性验证
  10. gitlab修改代码提交后显示中文名称