一、Zuul
路由网关
1. 是什么
- Zuul 是一种提供 动态路由、监视、弹性、安全性 等功能的边缘服务。
- Zuul 是 Netflix 出品的一个基于JVM 路由 和 服务端 的负载均衡器。
- API 网关 为微服务架构中的服务提供了 统一的访问入口,客户端通过 API 网关访问相关服务。
- API 网关的定义类似于设计模式中的门面模式,它相当于整个微服务架构中的门面,所有客户端的访问都通过它来进行路由及过滤。
- 它实现了 请求路由、负载均衡、校验过滤、服务容错、服务聚合 等功能。
- Zuul 包含了如下最主要的功能:代理 + 路由 + 过滤 三大功能。
2. 能干嘛
- 由于 Zuul 自动集成了 Ribbon 和 Hystrix。
所以 Zuul 天生就有 负载均衡 和 服务容错 的能力。
2.1 路由
2.2 过滤
2.3 负载均衡
- 网关为入口,由 网关 与 微服务 进行交互,所以网关必须要实现 负载均衡 的功能。
- 网关会获取 微服务注册中心 里面的服务连接地址,再配合一些算法选择其中一个服务地址,进行处理业务。
- 这个属于 客户端的负载均衡,由调用方去实现负载均衡逻辑。
2.4 灰度发布(又称金丝雀发布)
- 起源是,矿井工人发现金丝雀对瓦斯气体很敏感,矿工会在下井之前,先放一只金丝雀到井中,如果金丝雀不叫了,就代表瓦斯浓度高。
- 在灰度发布开始后,先启动一个新版本应用,但是并不直接将流量切过来,而是测试人员对新版本进行线上测试,启动的这个新版本应用,就是我们的金丝雀。
- 如果没有问题,那么可以将少量的用户流量导入到新版本上,然后再对新版本做运行状态观察,收集各种运行时数据,如果此时对新旧版本做各种数据对比,就是所谓的 A/B 测试。
- 新版本没什么问题,那么逐步扩大范围、流量,把所有用户都迁移到新版本上面来。
3. 路由基本配置
- 功能:路由功能负责将 外部请求 转发到 具体的服务实例 上去,是实现统一访问入口的基础。
3.1 新建 Module cloud-gateway-zuul9527
3.2 POM
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloud-2020</artifactId>
<groupId>com.qs.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-gateway-zuul9527</artifactId>
<dependencies>
<!--zuul-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--actuator-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</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>
</project>
3.3 YML
- 修改
hosts
文件。
# 添加映射配置
127.0.0.1 zuul9527.com
server:
port: 9527
spring:
application:
name: cloud-gateway-zuul
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka
instance:
instance-id: zuul9527.com
prefer-ip-address: true
3.4 主启动
@SpringBootApplication
@EnableZuulProxy
public class ZuulMain9527 {
public static void main(String[] args) {
SpringApplication.run(ZuulMain9527.class, args);
}
}
3.5 测试
- 不用路由。
http://localhost:8001/payment/get/1- 启用路由(Zuul 映射配置地址 + 注册中心注册后对外暴露的服务名称 + Rest 调用地址)
http://zuul9527.com:9527/provider-payment-service/payment/get/1
4. 路由访问映射
规则
4.1 配置代理名称
- 修改
YML
。
zuul:
# 路由映射配置(代理名称)
routes:
# 代理名称
mypayment.path: /provider/**
# 对应服务id
mypayment.serviceId: provider-payment-service
# 可以配置多个
mysms.path: /sms/**
mysms.serviceId: cloud-provider-sms
4.2 忽略原有真实服务名
- 修改
YML
。
zuul:
# 忽略原有真实服务名
# ignored-services: provider-payment-service
# 多个可以用 "*"
ignored-services: "*"
4.3 路由转发 和 负载均衡 功能
4.3.1 新建 Module cloud-provider-sms8008
4.3.2 POM
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloud-2020</artifactId>
<groupId>com.qs.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-provider-sms8008</artifactId>
<dependencies>
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--web + actuator-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</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>
</project>
4.3.3 YML
server:
port: 8008
# 服务名称(服务注册到Eureka名称)
spring:
application:
name: cloud-provider-sms
# 服务提供者cloud-provider-sms注册进Eureka服务列表内
eureka:
client:
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://eureka7001.com:7001/eureka
4.3.4 主启动
@SpringBootApplication
@EnableEurekaClient
public class SMSMain8008 {
public static void main(String[] args) {
SpringApplication.run(SMSMain8008.class, args);
}
}
4.3.5 SMSController
@RestController
public class SMSController {
@Value("${server.port}")
private String serverPort;
@GetMapping("/sms")
public String sms() {
return "sms: " + serverPort;
}
}
4.3.6 测试
http://zuul9527.com:9527/provider/payment/get/1 负载均衡(8001/8002)
http://zuul9527.com:9527/sms/sms 路由转发(8008)
5. 设置统一公共前缀
5.1 修改 YML
zuul:
# 设置统一公共前缀
prefix: /qs
5.2 测试
http://zuul9527.com:9527/qs/provider/payment/get/1
http://zuul9527.com:9527/qs/sms/sms
6. 查看路由信息
6.1 修改 POM
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
6.2 YML
# 开启查看路由的端点
management:
endpoints:
web:
exposure:
include: 'routes'
6.3 测试
7. 过滤器
- 过滤 功能负责对请求过程进行额外的处理,是 请求校验过滤 及 服务聚合 的基础。
- 过滤器的生命周期。
7.1 ZuulFilter
- 过滤类型。
- pre:在请求 被 路由到目标服务 前执行。
比如:权限校验、打印日志等功能。- routing:在请求 被 路由到目标服务 时执行。
- post:在请求 被 路由到目标服务 后执行。
比如:给目标服务的响应添加头信息,收集统计数据等功能。- error:请求在其他阶段 发生错误 时执行。
- 过滤顺序。
数字小的先执行。
- 过滤是否开启。
shouldFilter 方法为 true。
7.2 配置前置过滤器——打印日志
- 前置过滤器,用于在请求路由到 目标服务 前打印请求日志。
7.2.1 PreLogFilter
@Component
@Slf4j
public class PreLogFilter extends ZuulFilter {
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 1;
}
@Override
public boolean shouldFilter() {
return true;
}
/**
* 在调用之前会打印日志
*/
@Override
public Object run() throws ZuulException {
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
String host = request.getRemoteHost();
String method = request.getMethod();
String uri = request.getRequestURI();
log.info("host: {}, method: {}, uri: {}, date: {}", host, method, uri, new Date().getTime());
return null;
}
}
7.2.2 YML
zuul:
# 过滤器开关
PreLogFilter:
pre:
disable: false
7.2.3 测试
二、Gatewa
新一代网关
1. 是什么
- Cloud 全家桶中有个很重要的组件就是网关,在 1.x 版本中都是采用的 Zuul 网关。
- 但在 2.x 版本中,Zuul 的升级一直跳票,Spring Cloud 最后自己研发了一个网关替代 Zuul,那就是 Spring Cloud Gateway 一句话:Gateway 是原 Zuul1.x 版的替代。
- Gateway 是在 Spring 生态系统之上构建的 API 网关服务,基于 Spring-5.0,Spring Boot-2.0 和 Project Reactor 等技术。
- Gateway 旨在提供一种简单而有效的方式来对 API 进行路由,以及提供一些强大的过滤器功能。
例如:熔断、限流、重试 等。
- Spring Cloud Gateway 是 Spring Cloud 的一个全新项目,基于 Spring-5.0,Spring Boot-2.0 和 Project Reactor 等技术开发的网关。
它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。- Spring Cloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Zuul。
在 Spring Cloud-2.0 以上版本中,没有对新版本的 Zuul-2.0 以上最新高性能版本进行集成,仍然还是使用的 Zuul-1.x 非 Reactor 模式的老版本。
而为了提升网关的性能,Spring Cloud Gateway 是基于 WebFlux 框架实现的,而 WebFlux 框架底层则使用了高性能的 Reactor 模式通信框架 Netty。- Spring Cloud Gateway 的目标提供统一的路由方式且基于 Filter 链 的方式提供了网关基本的功能。
例如:安全,监控/指标,和限流。- 一句话:Spring Cloud Gateway 使用的 WebFlux 中的 reactor-netty 响应式编程组件,底层使用了 Netty 通讯框架。
2. 能干嘛
2.1 反向代理
2.2 鉴权
2.3 流量控制
2.4 熔断
2.5 日志监控
3. 微服务架构中网关在哪里
4. 有了 Zuul
怎么又出来了 Gateway
4.1 我们为什么选择 Gateway
?
- Neflix 不太靠谱,Zuul-2.0 一直跳票,迟迟不发布。
- 一方面因为 Zuul-1.0 已经进入了维护阶段,而且 Gateway 是 Spring Cloud 团队研发的,是亲儿子产品,值得信赖。
而且很多功能 Zuul 都没有,用起来也非常的简单便捷。- Gateway 是基于 异步非阻塞模型上 进行开发的,性能方面不需要担心。
虽然 Netflix 早就发布了最新的 Zuul-2.x,但 Spring Cloud 貌似没有整合计划。
而且 Netflix 相关组件都宣布进入维护期;不知前景如何?- 多方面综合考虑 Gateway 是很理想的网关选择。
- Spring Cloud Gateway 具有如下特性。
- 基于 Spring Framework-5.0,Project Reactor 和 Spring Boot-2.0 进行构建。
- 动态路由:能够匹配任何请求属性。
- 可以对路由指定 Predicate(断言)和 Filter(过滤器)。
- 集成 Hystrix 的断路器功能。
- 集成 Spring Cloud 服务发现功能。
- 易于编写的 Predicate(断言)和 Filter(过滤器)。
- 请求限流功能。
- 支持路径重写。
- Spring Cloud Gateway 与 Zuul 的区别。
- 在 Spring Cloud Finchley 正式版之前,Spring Cloud 推荐的网关是 Netflix 提供的 Zuul。
- Zuul-1.x 是一个基于阻塞 I/O 的 API Gateway。
- Zuul-1.x 基于 Servlet-2.5 使用阻塞架构 它不支持任何长连接(如:WebSocket)。
Zuul 的设计模式 和 Nginx 较像,每次 I/O 操作都是从工作线程中选择一个执行,请求线程被阻塞到工作线程完成。
但是差别是 Nginx 用 C++ 实现,Zuul 用 Java 实现。
而 JVM 本身会有第一次加载较慢的情况,使得 Zuul 的性能相对较差;- Zuul-2.x 理念更先进,想基于 Netty 非阻塞 和 支持长连接,但 Spring Cloud 目前还没有整合。
Zuul-2.x 的性能较 Zuul-1.x 有较大提升。
在性能方面,根据官方提供的基准测试,Spring Cloud Gateway 的 RPS(每秒请求数)是 Zuul 的 1.6 倍。- Spring Cloud Gateway 建立在 Spring Framework-5.0、Project Reactor 和 Spring Boot-2.0之上,使用非阻塞 API。
- Spring Cloud Gateway 还支持 WebSocket,并且与 Spring 紧密集成拥有更好的开发体验。
4.2 Zuul-1.x
模型
- Spring Cloud 中所集成的 Zuul 版本,采用的是 Tomcat 容器。
使用的是传统的 Servlet IO 处理模型。
- Servlet 的生命周期?
- Servlet 由 Servlet Container 进行生命周期管理。
- Container 启动时,构造 Servlet 对象并调用
Servlet.init()
进行初始化。- Container 运行时,接受请求并为每个请求分配一个线程(一般从线程池中获取空闲线程)然后调用
service()
。- Container 关闭时,调用
Servlet.destory()
销毁 Servlet。
- 上述模式的缺点。
- Servlet 是一个简单的网络 IO 模型,当请求进入 Servlet Container 时,Servlet Container 就会为其绑定一个线程,在 并发不高的场景下 这种模型是适用的。
但是一旦高并发(比如:用 JMeter 压测),线程数量就会上涨,而线程资源代价是昂贵的(上线文切换,内存消耗大)严重影响请求的处理时间。
在一些简单业务场景下,不希望为每个 Request 分配一个线程,只需要 1 个或几个线程就能应对极大并发的请求,这种业务场景下 Servlet 模型没有优势。- 所以 Zuul-1.X 是基于 Servlet 之上的一个阻塞式处理模型。
即 Spring 实现了处理所有 Request 请求的一个 Servlet(DispatcherServlet)并由该 Servlet 阻塞式处理处理。
所以 Spring Cloud Zuul 无法摆脱 Servlet 模型的弊端。
4.3 Gateway
模型
- 传统的 Web 框架,比如说:Struts2,SpringMVC 等都是基于 Servlet API 与 Servlet 容器基础之上运行的。
- 但是 在 Servlet-3.1 之后有了 异步非阻塞 的支持。
而 WebFlux 是一个典型 异步非阻塞 的框架,它的核心是基于 Reactor 的相关 API 实现的。
相对于传统的 Web 框架来说,它可以运行在诸如 Netty,Undertow 及支持 Servlet-3.1 的容器上。
非阻塞式 + 函数式编程(Spring-5.0 必须让你使用 Java-8)。- Spring WebFlux 是 Spring-5.0 引入的新的响应式框架,区别于 Spring MVC。
它不需要依赖 Servlet API,它是完全异步非阻塞的,并且基于 Reactor 来实现响应式流规范。
5. 三大核心概念
5.1 Route
(路由)
- 路由是构建网关的基本模块,它由 ID,目标 URI,一系列的 断言 和 过滤器 组成。
如果断言为 true 则匹配该路由。
5.2 Predicate
(断言)
- 参考的是 Java-8 的
java.util.function.Predicate
,开发人员可以匹配 HTTP 请求中的所有内容(例如:请求头 或 请求参数),如果请求与 断言 相匹配则进行路由。
5.3 Filter
(过滤)
- 指的是 Spring 框架中 Gateway Filter 的实例。
使用过滤器,可以在请求被 路由前 或者 之后 对请求进行修改。
5.4 Route + Predicate + Filter
- Web 请求通过一些匹配条件,定位到真正的服务节点。
并在这个转发过程的前后,进行一些精细化控制。
- Predicate 就是我们的匹配条件。
- 而 Filter 就可以理解为一个无所不能的拦截器。
- 有了这两个元素,再加上目标 URI,就可以实现一个具体的路由了。
6. Gateway
工作流程
- 客户端向 Spring Cloud Gateway 发出请求。
然后在 Gateway Handler Mapping 中找到与请求 相匹配的路由,将其发送到 Gateway Web Handler。- Handler 再通过指定的过滤器链,来将请求发送到我们实际的服务执行业务逻辑,然后返回。
- 过滤器之间用虚线分开,是因为过滤器可能会在发送代理请求之前(pre)或之后(post)执行业务逻辑。
- Filter 在 “pre” 类型的过滤器可以做 参数校验、权限校验、流量监控、日志输出、协议转换 等。
- 在 “post” 类型的过滤器中可以做 响应内容、响应头的修改,日志的输出,流量监控等有着非常重要的作用。
- 核心逻辑:路由转发 + 执行过滤器链
7. 入门配置
7.1 新建 Module cloud-gateway-gateway9527
7.2 POM
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloud-2020</artifactId>
<groupId>com.qs.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-gateway-gateway9527</artifactId>
<dependencies>
<!--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>
<!--自定义API通用包-->
<dependency>
<groupId>com.qs.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</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>
</project>
7.3 YML
server:
port: 9527
spring:
application:
name: cloud-gateway-gateway
cloud:
# 配置Gateway
gateway:
# 一、路由
routes:
# payment_route 路由的id,没有固定规则,但要求唯一,建议配合服务名
- id: payment_routh
# uri 目标服务地址,匹配后提供服务的路由地址
uri: http://localhost:8001
predicates:
# 断言,路径相匹配的进行路由
- Path=/payment/get/**
- id: payment_routh2
uri: http://localhost:8001
predicates:
- Path=/payment/lb/**
eureka:
instance:
hostname: cloud-gateway-gateway
client:
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://eureka7001.com:7001/eureka
7.4 主启动
@SpringBootApplication
@EnableEurekaClient
public class GateWayMain9527 {
public static void main(String[] args) {
SpringApplication.run(GateWayMain9527.class, args);
}
}
7.5 测试
http://localhost:8001/payment/lb 添加网关前
http://localhost:9527/payment/lb 添加网关后
8. Gateway
网关路由有两种配置方式
8.1 YML
配置(参考上面)
8.2 代码中注入 RouteLocator
的 Bean
@Configuration
public class GateWayConfig {
/**
* 配置了一个id为route-name的路由规则
* 当访问地址:http://localhost:9527/guonei
* 会自动转发到地址:http://news.baidu.com/guonei
*/
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
RouteLocatorBuilder.Builder routes = builder.routes();
routes.route("path_route_guonei", r -> r.path("/guonei").uri("http://news.baidu.com/guonei")).build();
return routes.build();
}
@Bean
public RouteLocator customRouteLocator2(RouteLocatorBuilder builder) {
RouteLocatorBuilder.Builder routes = builder.routes();
routes.route("path_route_guoji", r -> r.path("/guoji").uri("http://news.baidu.com/guoji")).build();
return routes.build();
}
}
8.3 测试
9. 通过 微服务名 实现动态路由
- 默认情况下 Gateway 会根据注册中心注册的服务列表,以注册中心上 微服务名 为路径创建 动态路由进行转发,从而实现动态路由的功能。
- 需要注意的是 uri 的协议为 lb,表示启用 Gateway 的负载均衡功能。
lb://serviceName
是 Spring Cloud Gateway 在微服务中自动为我们创建的负载均衡 uri。
9.1 修改 YML
spring:
cloud:
# 配置Gateway
gateway:
# 通过微服务名实现动态路由
discovery:
locator:
# true 表示开启从注册中心动态创建路由的功能,利用微服务名进行路由
enabled: true
# 一、路由
routes:
- id: payment_routh2
# uri: http://localhost:8001
# lb://serviceName是 Spring Cloud Gateway在微服务中自动为我们创建的负载均衡uri
uri: lb://provider-payment-service
predicates:
- Path=/payment/lb/**
9.2 测试
http://localhost:9527/payment/lb 8001/8002两个端口切换
10. Predicate
的使用
10.1 是什么
- 启动我们的
gateway9527
。
10.2 Route Predicate Factories
这个是什么?
- Spring Cloud Gateway 将路由匹配作为 Spring WebFlux HandlerMapping 基础架构的一部分。
- Spring Cloud Gateway 包括许多内置的 Route Predicate工厂。
所有这些 Predicate 都与 HTTP 请求的不同属性匹配。
多个 Route Predicate 工厂可以进行组合。- Spring Cloud Gateway 创建 Route 对象时,使用 RoutePredicateFactory 创建 Predicate 对象,Predicate 对象可以赋值给 Route。
Spring Cloud Gateway 包含许多内置的 Route Predicate Factories。- 所有这些谓词都匹配 HTTP 请求的不同属性。
多种谓词工厂可以组合,并通过逻辑 and。
10.3 常用的 Route Predicate
10.3.1 After
Route Predicate
predicates:
# 1. 在某个时间之后可访问
- After=2021-08-28T19:49:32.007+08:00[Asia/Shanghai]
- 我们的问题是:上述这个After好懂,这个时间串串?
// 默认时区
ZonedDateTime zbj = ZonedDateTime.now();
// 指定时区获取当前时间
ZonedDateTime zny = ZonedDateTime.now(ZoneId.of("America/New_York"));
10.3.2 Before
Route Predicate
predicates:
# 2. 在某个时间之前可路由
- Before=2021-08-29T19:49:32.007+08:00[Asia/Shanghai]
10.3.3 Between
Route Predicate
predicates:
# 3. 在某个时间段之间可路由
- Between=2021-08-28T19:49:32.007+08:00[Asia/Shanghai],2021-08-29T19:49:32.007+08:00[Asia/Shanghai]
10.3.4 Cookie
Route Predicate
- Cookie Route Predicate 需要两个参数,一个是 Cookie name,一个是正则表达式。
- 路由规则会通过获取对应的 Cookie name 值 和 正则表达式去匹配,如果匹配上就会执行路由,如果没有匹配上则不执行。
predicates:
# 4. 携带--cookie "username=zzyy"可路由
- Cookie=username,zzyy
- 不带 Cookie 访问。
curl http://localhost:9527/payment/lb
- 带上
Cookie
访问。
加入curl返回中文乱码
curl http://localhost:9527/payment/lb --cookie "username=zzyy"
10.3.5 Header
Route Predicate
- 两个参数:一个是属性名称 和 一个正则表达式,这个 属性值 和 正则表达式 匹配则执行。
predicates:
# 5. 请求头要有X-Request-Id属性,并且值为正数的正则表达式可路由
- Header=X-Request-Id, \d+
curl http://localhost:9527/payment/lb -H "X-Request-Id:123"
10.3.6 Host
Route Predicate
- Host Route Predicate 接收一组参数,一组匹配的域名列表,这个模板是一个 ant 分隔的模板,用
.
号作为分隔符。- 它通过参数中的 主机地址 作为匹配规则。
predicates:
# 6. 请求头要有Host属性,并且.qs.com结尾可路由
- Host=**.qs.com
curl http://localhost:9527/payment/lb -H "Host: www.qs.com"
正确
curl http://localhost:9527/payment/lb -H "Host: java.qs.com"
正确
curl http://localhost:9527/payment/lb -H "Host: java.qs.net"
错误
10.3.7 Method
Route Predicate
predicates:
# 7. 限制为GET请求可路由
- Method=GET
10.3.8 Path
Route Predicate
predicates:
# 8. 匹配路径的进行路由
- Path=/payment/lb/**
10.3.9 Query
Route Predicate
支持传入两个参数,一个是属性名,一个为属性值,属性值可以是正则表达式。
predicates:
# 9. 要有参数名username,并且值为正数可路由
- Query=username, \d+
http://localhost:9527/payment/lb?username=31
http://localhost:9527/payment/lb?username=-31
10.3.10 断言 All
配置
- 说白了,Predicate 就是为了实现一组匹配规则,让请求过来找到对应的 Route 进行处理。
# 二、断言`All`配置
# predicates 路由条件,接受一个输入参数返回一个布尔值,该属性包含多种默认方法来将 Predicate组合成其他复杂的逻辑(比如:与、或、非)
predicates:
# 1. 在某个时间之后可路由
# - After=2021-08-28T19:49:32.007+08:00[Asia/Shanghai]
# 2. 在某个时间之前可路由
# - Before=2021-08-29T19:49:32.007+08:00[Asia/Shanghai]
# 3. 在某个时间段之间可路由
- Between=2021-08-28T19:49:32.007+08:00[Asia/Shanghai],2021-08-29T19:49:32.007+08:00[Asia/Shanghai]
# 4. 携带--cookie "username=zzyy"可路由
- Cookie=username,zzyy
# 5. 请求头要有X-Request-Id属性,并且值为正数的正则表达式可路由
- Header=X-Request-Id, \d+
# 6. 请求头要有Host属性,并且.qs.com结尾可路由
- Host=**.qs.com
# 7. 限制为GET请求可路由
- Method=GET
# 8. 匹配路径的进行路由
- Path=/payment/lb/**
# 9. 要有参数名username,并且值为正数可路由
- Query=username, \d+
11. Filter
的使用
11.1 是什么
- 路由过滤器可用于修改进入的 HTTP 请求 和 返回的 HTTP 响应,路由过滤器只能指定路由进行使用。
- Spring Cloud Gateway 内置了多种路由过滤器,他们都由 Gateway Filter 的工厂类来产生。
11.2 Spring Cloud Gateway 的 Filter
- 生命周期。
pre
前置。post
后置。
- 种类。
- GatewayFilter(31 种)单一
- GlobalFilter(10 种)全局
11.3 常用的 Gateway Filter
- AddRequestParameter。
spring:
cloud:
# 配置Gateway
gateway:
# 通过微服务名实现动态路由
discovery:
locator:
# true 表示开启从注册中心动态创建路由的功能,利用微服务名进行路由
enabled: true
# 使用小写服务名,默认是大写
lower-case-service-id: true
routes:
- id: payment_routh1
uri: lb://provider-payment-service
predicates:
- Path=/paymentInfo/**
- Method=GET,POST
# 三、过滤器(GatewayFilter31 + GlobalFilter10)
filters:
# GatewayFilter > AddRequestParameter,过滤器工厂会在匹配的请求头加上一对请求头,名称为`X-Request-Id`值为`1024`
- AddRequestParameter=X-Request-Id,1024
11.4 自定义全局过滤器
- 全局日志记录。
- 统一网关鉴权。
@Component
public class MyLogGateWayFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("time:" + new Date() + ",执行了自定义的全局过滤器:" + "MyLogGateWayFilter");
String uname = exchange.getRequest().getQueryParams().getFirst("uname");
if (uname == null) {
System.out.println("用户名为空");
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
// 放行
return chain.filter(exchange);
}
@Override
public int getOrder() {
// 数字越小,优先级越高
return 0;
}
}
- 测试。
http://localhost:9527/payment/lb?uname=z3 正确
http://localhost:9527/payment/lb 错误,没有参数uname