6. Spring Cloud Gateway网关超详细内容配置解析说明
文章目录
前言
- 对应上一篇学习内容:🌟🌟🌟5. Spring Cloud OpenFeign 声明式 WebService 客户端的超详细使用-CSDN博客
- 对应下一篇学习内容:🌟🌟🌟
看一个需求,引出网关服务
有一个前后端分离项目, 分析如图:
使用网关服务 重构项目架构
分布式微服务网络拓扑图:
1 Spring Cloud Gateway 概述
Gateway 是什么:
- Gateway 是Spring 生态系统之上构建的 API 网关服务,基于 Spring ,Spring Boot 和 Project Reactor 等技术。
- GateWay 旨在提供一种简单而有效的方式来对 API 进行路由,以及提供一些强大的过滤器功能,例如:熔断,限流,重试等。
Spring Cloud Gateway 官网地址:https://docs.spring.io/spring-cloud-gateway/reference/
Spring Cloud Gateway 官网地址:https://spring.io/projects/spring-cloud-gateway#learn
1.1 Spring Cloud Gateway网关 的核心功能
Spring Cloud Gateway 的核心功能是:
- 路由转发:Spring Cloud Gateway的主要功能是将客户端的请求路由到后端的具体服务上。它通过定义路由规则,根据请求的URI和其他条件将请求转发到相应的微服务。
- 过滤和修改请求:在请求被路由之前或之后,Spring Cloud Gateway可以对请求进行过滤和修改。过滤器可以添加或修改请求头、验证身份、进行日志记录等。
- 限流和熔断:在请求流量过高时,Spring Cloud Gateway可以进行限流,按照下游微服务能够接受的速度来放行请求,避免服务压力过大。此外,它还支持熔断功能,在微服务不可用或出现故障时,阻止请求继续发送,并提供降级功能。
- 动态路由:Spring Cloud Gateway支持动态路由配置(Eureka 集群),可以在网关运行过程中更改路由配置,提高了系统的灵活性和可维护性。
- 服务发现:它与服务注册中心(如[Eureka] 的核心功能是Spring Cloud Gateway 的核心功能是集成,自动发现可用的微服务实例,简化了服务的部署和维护。
- 安全性:Spring Cloud Gateway可以作为整个微服务架构的防火墙和代理器,隐藏微服务节点的IP和端口信息,增强服务调用的安全性。
- 监控和日志记录:它支持对请求进行监控和日志记录,帮助开发者更好地了解系统的运行状态和调试问题。
网关的基本功能:
- 网关核心功能是路由转发,因此不要有耗时操作在网关上处理,让请求快速转发到后端服务上。
- 网关还能做统一的熔断,限流,认证,日志监控等。
Spring Cloud GateWay 特性
Spring Cloud Gateway 基于 Spring FrameWork(支持Spring WebFlux),Project Reactor 和 Spring Boot 进行构建,具有如下特性:
- 动态路由
- 可以对路由指定 Predicate(断言)和Filter(过滤器)
- 集成 Hystric 的断路器功能
- 集成 Spring Cloud 服务发现功能
- 请求限流功能
- 支持路径重写
1.2 Spring Cloud Gateway VS Zuul 的区别
Gateway 和 Zuul 区别:
- Spring Cloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Zuul。
- SpringCloud Gateway 是基于 Spring WebFlux 框架实现的。
- Spring WebFlux 框架底层则使用了高性能的 Reactor模式通信框架Netty,提升了网关性能。
1.3 Spring Cloud Gateway 的基本原理
Spring Cloud Gateway 核心组件:如下图
解读:
- Web 请求,通过一些匹配条件,定位到真正的服务节点/微服务模块,在这个转发过程的前后,进行一些精细化控制。
- predicate:就是匹配条件。
- filter:可以理解为是网关的过滤机制。有了 predicate 和 filter ,再加上目标 url 就可以实现一个具体的路由。
Spring Cloud Gateway 的三大核心组件 Route(路由),Predicate(断言),Filter(过滤)
Route(路由)
一句话:路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为 true 则匹配该路由。
Predicate(断言)
一句话:对HTTP请求中所有内容(例如请求头或请求参数)进行匹配,如果请求与断言相匹配则进行路由。
简单的举例:比如配置路径为:
-Path=/member/get/**
# 断言,路径相匹配的进行路由转发,如果Http请求的路径不匹配,则不进行路由转发。
Filter(过滤)
一句话:使用过滤器,可以在请求被路由前或者之后 对请求进行处理。
你可以理解成,在对HTTP请求断言匹配成功后,可以通过网关的过滤机制,对HTTP请求处理。
简单举例:
filters:
- AddRequestParameter=color,blue
# 过滤器在匹配的请求头加上一对请求头,名称为color值为 blue,比 如 原 来 的 http 请 求 是 http://localhost:10000/member/get/1 == 过 滤 器 处 理 => http://localhost:10000/member/get/1?color=blue
1.4 Spring Cloud Gateway (How It Works 工作机制)
- 客户端向 Spring Cloud Gateway 发出请求,然后在 Gateway Handler Mapping 中找到与请求相匹配的路由,将其发送到 GateWay Web Handler。
- Handler 再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。
- 过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前(“pre”) 或之后(“post”) 执行业务。
- Filter 在“pre” 类型的过滤器可以做参数校验,权限校验,流量监控,日志输出,协议转换等。
- 在 “post” 类型的过滤器中可以做响应内容,响应头的修改,日志的输出,流量监控等有着非常非常重要的作用。一句话说: 路由转发+执行过滤器链。
2. Spring Cloud Gateway组件当中的“Routing(路由)”(搭建 Spring Cloud Gateway 微服务)
搭建 Gateway-应用实例;需求分析/图解;引入 Gateway 项目架构
- 通过网关暴露的接口,实现调用真正的服务
- 网关本身也是一个微服务模块
- 参考 member-service-consumer-80 创建 e-commerce-gateway-20000(具体步骤参考以 前)
- 修改 pom.xml, 部分内容可以从 member-service-consumer-80 的 pom.xml 拷贝
pom.xml 编写内容,如下:
<?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>e-commerce-center</artifactId>
<groupId>com.rainbowsea</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>e-commerce-gateway-20000</artifactId>
<!-- 引入相关的依赖:我们引入了当前所需要的依赖,后面如果有其它的需要,再灵活添加-->
<dependencies>
<!-- 引入 gateway-starter 网关场景启动器 starter:使用版本仲裁(从父项目继承了版本)-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- 1. 特别提示: 不要引入Spring-boot-starter-web 和 spring-boot-starter-actuator-->
<!-- 2. 因为 gateway 是一个服务网关,不需要 web...-->
<!-- 引入 web-starter 说明:我们使用版本仲裁(从父项目继承了版本)-->
<!--<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>-->
<!--1. starter-actuator 是spring boot 程序的监控系统,可以实现健康检查,info 信息等
2. 访问http://localhost:10000/actuator 可以看到相关链接,还可以做相关配置-->
<!-- <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>-->
<!-- lombok 引入-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 引入 test-starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 引入我们自己对 bean 封装成 api 的模块内容-->
<dependency>
<groupId>com.rainbowsea</groupId>
<artifactId>e_commerce_center-common-api</artifactId>
<version>${project.version}</version>
</dependency>
<!-- 引入 eureka-client 依赖 -->
<!-- 注意:存在一个 starter 不要选错了-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
</project>
特别提醒:
- 不要引入 Spring-boot-starter-web 和 spring-boot-starter-actuator ,因为 gateway 是一个服务网关,不需要 web…,引入 web-starter 说明:我们使用版本仲裁(从父项目继承了版本)。
配置 Spring Cloud Gateway 的 Routing(路由)有两种方式:
- 第一种方式:通过
application.yaml
配置文件的的方式,配置Routing(路由) - 第二种方式:通过定义配置类的方式,配置Routing(路由)
2.1 第一种方式:通过 application.yaml
配置文件的的方式,配置Routing(路由)
在类路径下(resources)下,创建 application.yml(重点核心) ,配置 Spring Cloud Gateway 组件内容如下:
server:
port: 20000
spring:
application:
name: e-commerce-gateway
cloud:
# 配置 Spring Cloud Gateway 内容
gateway:
routes: # 配置路由,可以配置多个路由 List<RouteDefinition> routes
- id: member_route01 # 路由的id,程序员自己配置,要求唯一
uri: http://localhost:10000 # 路由的id,程序员自己配置,要求"唯一"
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
- Path=/member/get/**
yaml 当中的 Spring Cloud Gateway 配置说明:
server:
port: 20000
spring:
application:
name: e-commerce-gateway
cloud:
# 配置 Spring Cloud Gateway 内容
gateway:
routes: # 配置路由,可以配置多个路由 List<RouteDefinition> routes
- id: member_route01 # 路由的id,程序员自己配置,要求唯一
# gateway 最终访问的url是 url=url+Path
# 匹配后提供服务的路由地址:也可以是外网 http://www.baidu.com
# 这里我们匹配为一个 localhost:10000 服务即可
# 比如: 客户端/浏览器请求: url http://localhost:20000/member/get/1
# 如果根据Path匹配成功,最终访问的url/转发url就是 url=http://localhost:10000/member/get/1
# 如果匹配失败,则有 gateway 返回 404信息
# 疑问: 这里老师配置的 url 是固定的,在当前这种情况其实可以不是有 Eureka Server,
# 后面老师会使用灵活配置的方式,配置,就会使用 Eureka Server
# 注意:当这里我们仅仅配置了一个url 的时候,就只会将信息转发到这个10000服务端,为我们处理业务,
# 一个服务就没有(轮询)的负载均衡了
# uri: http://localhost:10000
# 将查询服务,配置为动态的服务(轮询)负载均衡
# 2. 默认情况下,负载均衡算法是轮询
uri: http://localhost:10000 # 路由的id,程序员自己配置,要求"唯一"
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
- Path=/member/get/**
yaml 完整内容:
server:
port: 20000
spring:
application:
name: e-commerce-gateway
cloud:
# 配置 Spring Cloud Gateway 内容
gateway:
routes: # 配置路由,可以配置多个路由 List<RouteDefinition> routes
- id: member_route01 # 路由的id,程序员自己配置,要求唯一
# gateway 最终访问的url是 url=url+Path
# 匹配后提供服务的路由地址:也可以是外网 http://www.baidu.com
# 这里我们匹配为一个 localhost:10000 服务即可
# 比如: 客户端/浏览器请求: url http://localhost:20000/member/get/1
# 如果根据Path匹配成功,最终访问的url/转发url就是 url=http://localhost:10000/member/get/1
# 如果匹配失败,则有 gateway 返回 404信息
# 疑问: 这里老师配置的 url 是固定的,在当前这种情况其实可以不是有 Eureka Server,
# 后面老师会使用灵活配置的方式,配置,就会使用 Eureka Server
# 注意:当这里我们仅仅配置了一个url 的时候,就只会将信息转发到这个10000服务端,为我们处理业务,
# 一个服务就没有(轮询)的负载均衡了
# uri: http://localhost:10000
# 将查询服务,配置为动态的服务(轮询)负载均衡
# 2. 默认情况下,负载均衡算法是轮询
uri: http://localhost:10000 # 路由的id,程序员自己配置,要求"唯一"
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
- Path=/member/get/**
# 配置 Eureka-Client
eureka:
instance:
hostname: e-commerce-service
client:
register-with-eureka: true # 将自己注册到 Eureka-Server 注册中心当中
fetch-registry: true
service-url:
# 表示将自己注册到哪个 eureka-server
# 这里我们将本微服务注册到EurekaServer 集群,使用","逗号间隔
# 这里为了方便,使用 Eureka Server 的单个服务环境进行测试,不采用集群的方式
defaultZone: http://eureka9001.com:9001/eureka/
创建主启动类 com/hspedu/springcloud/GateWayApplication20000.java
package com.rainbowsea.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient // 标注为 Eureka Client 角色
public class GateWayApplication20000 {
public static void main(String[] args) {
SpringApplication.run(GateWayApplication20000.class, args);
}
}
测试:
- e-commerce-eureka-server-9001
- 启动 member-service-provider-10000
- 启动 e-commerce-gateway-20000
- 浏览器:(通过网关访问) http://localhost:20000/member/get/1 ,浏览器输入: http://localhost:20000/member/get/1
对于 Routing(路由),我们是可以配置多个请求路径的路由信息的,如下我们配置再额外配置一个 /member/save
保存路径 如下图所示:
server:
port: 20000
spring:
application:
name: e-commerce-gateway
cloud:
# 配置 Spring Cloud Gateway 内容
gateway:
routes: # 配置路由,可以配置多个路由 List<RouteDefinition> routes
- id: member_route01 # 路由的id,程序员自己配置,要求唯一
uri: http://localhost:10000
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
- Path=/member/get/**
# 配置: 第二个请求路径映射路由
- id: member_route02 # 路由的id,程序员自己配置,要求"唯一"
uri: http://localhost:10000
# 配置(轮询负载均衡)动态调用服务器
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
# 这时如果客户端/浏览器 访问 gateway 的url http://localhost:20000/member/save
# 匹配Path成功 最终访问的url就是 ; http://localhost:10000/member/save 给对对应配置转发的10000服务处理了
- Path=/member/save
server:
port: 20000
spring:
application:
name: e-commerce-gateway
cloud:
# 配置 Spring Cloud Gateway 内容
gateway:
routes: # 配置路由,可以配置多个路由 List<RouteDefinition> routes
- id: member_route01 # 路由的id,程序员自己配置,要求唯一
uri: http://localhost:10000
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
- Path=/member/get/**
# 配置: 第二个请求路径映射路由
- id: member_route02 # 路由的id,程序员自己配置,要求"唯一"
uri: http://localhost:10000
# 配置(轮询负载均衡)动态调用服务器
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
# 这时如果客户端/浏览器 访问 gateway 的url http://localhost:20000/member/save
# 匹配Path成功 最终访问的url就是 ; http://localhost:10000/member/save 给对对应配置转发的10000服务处理了
- Path=/member/save
# 配置 Eureka-Client
eureka:
instance:
hostname: e-commerce-service
client:
register-with-eureka: true # 将自己注册到 Eureka-Server 注册中心当中
fetch-registry: true
service-url:
# 表示将自己注册到哪个 eureka-server
# 这里我们将本微服务注册到EurekaServer 集群,使用","逗号间隔
# 这里为了方便,使用 Eureka Server 的单个服务环境进行测试,不采用集群的方式
defaultZone: http://eureka9001.com:9001/eureka/
运行测试:
- e-commerce-eureka-server-9001
- 启动 member-service-provider-10000
- 启动 e-commerce-gateway-20000
- Postman 测试添加(走网关) 请求地址: http://localhost:20000/member/save
同时对于 Routing(路由),不仅仅是可以配置为我们自己的服务器上处理,也可以配置为其他外网的服务处理,比如百度,搜狗等等,这里我们演示配置百度的 url 路由映射 。
server:
port: 20000
spring:
application:
name: e-commerce-gateway
cloud:
# 配置 Spring Cloud Gateway 内容
gateway:
routes: # 配置路由,可以配置多个路由 List<RouteDefinition> routes
- id: member_route01 # 路由的id,程序员自己配置,要求唯一
uri: http://localhost:10000
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
- Path=/member/get/**
# 配置: 第二个请求路径映射路由
- id: member_route02 # 路由的id,程序员自己配置,要求"唯一"
uri: http://localhost:10000
# 配置(轮询负载均衡)动态调用服务器
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
# 这时如果客户端/浏览器 访问 gateway 的url http://localhost:20000/member/save
# 匹配Path成功 最终访问的url就是 ; http://localhost:10000/member/save 给对对应配置转发的10000服务处理了
- Path=/member/save
# 配置: 第三个以百度作为映射路由:
# 配置为,访问百度的网址,注意看这里,我们的 path 是 / ,也就是首页,不写任何的信息内容
- id: member_route03 # 路由的id,程序员自己配置,要求"唯一"
uri: http://www.baidu.com
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
- Path=/
server:
port: 20000
spring:
application:
name: e-commerce-gateway
cloud:
# 配置 Spring Cloud Gateway 内容
gateway:
routes: # 配置路由,可以配置多个路由 List<RouteDefinition> routes
- id: member_route01 # 路由的id,程序员自己配置,要求唯一
uri: http://localhost:10000
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
- Path=/member/get/**
# 配置: 第二个请求路径映射路由
- id: member_route02 # 路由的id,程序员自己配置,要求"唯一"
uri: http://localhost:10000
# 配置(轮询负载均衡)动态调用服务器
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
# 这时如果客户端/浏览器 访问 gateway 的url http://localhost:20000/member/save
# 匹配Path成功 最终访问的url就是 ; http://localhost:10000/member/save 给对对应配置转发的10000服务处理了
- Path=/member/save
# 配置: 第三个以百度作为映射路由:
# 配置为,访问百度的网址,注意看这里,我们的 path 是 / ,也就是首页,不写任何的信息内容
- id: member_route03 # 路由的id,程序员自己配置,要求"唯一"
uri: http://www.baidu.com
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
- Path=/
# 配置 Eureka-Client
eureka:
instance:
hostname: e-commerce-service
client:
register-with-eureka: true # 将自己注册到 Eureka-Server 注册中心当中
fetch-registry: true
service-url:
# 表示将自己注册到哪个 eureka-server
# 这里我们将本微服务注册到EurekaServer 集群,使用","逗号间隔
# 这里为了方便,使用 Eureka Server 的单个服务环境进行测试,不采用集群的方式
defaultZone: http://eureka9001.com:9001/eureka/
运行测试:
- e-commerce-eureka-server-9001
- 启动 member-service-provider-10000
- 启动 e-commerce-gateway-20000
- 浏览器地址栏上输入: http://localhost:20000/
2.2 第二种方式:通过定义配置类的方式,配置Routing(路由)
特别说明:这里我们测试通过配置类的方式,配置 Routing(路由)的方式,需要将我们前面的
application.yaml
当中配置的路由注释掉,不然,两个路由会存在冲突性的。
package com.rainbowsea.springcloud.config;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 配置类-配置路由
*/
@Configuration // 标注配置类
public class GateWayRoutesConfig {
// 注意:编写了配置类的方式配置路由,则需要将 application.yaml 文件当中配置的路由注释掉
@Bean // 注入到 ioc 容器当中管理起来
public RouteLocator myRouteLocator04(RouteLocatorBuilder routeLocatorBuilder) {
RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
// 方法写
return routes.route("member_route04",
r -> r.path("/member/get/**")
.uri("http://localhost:10000"))
.build();
}
}
/*
1. 是一个函数式接口
2. 接收的类型是: PredicateSpec, 返回的类型是 Route.AsyncBuilder
3. r -> r.path("/member/get/**")
.uri("http://localhost:10000"))
*/
- e-commerce-eureka-server-9001
- 启动 member-service-provider-10000
- 启动 e-commerce-gateway-20000
- 浏览器地址栏上输入: http://localhost:20000/memter/get/1
package com.rainbowsea.springcloud.config;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 配置类-配置路由
*/
@Configuration // 标注配置类
public class GateWayRoutesConfig {
// 注意:编写了配置类的方式配置路由,则需要将 application.yaml 文件当中配置的路由注释掉
@Bean // 注入到 ioc 容器当中管理起来
public RouteLocator myRouteLocator04(RouteLocatorBuilder routeLocatorBuilder) {
RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
// 方法写
return routes.route("member_route04",
r -> r.path("/member/get/**")
.uri("http://localhost:10000"))
.build();
}
/*
1. 是一个函数式接口
2. 接收的类型是: PredicateSpec, 返回的类型是 Route.AsyncBuilder
3. r -> r.path("/member/get/**")
.uri("http://localhost:10000"))
*/
@Bean
public RouteLocator
myRouteLocator02(RouteLocatorBuilder
routeLocatorBuilder) {
RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
return routes.route("member_route05", r -> r.path("/member/save")
.uri("http://localhost:10000")).build();
}
}
2.3 配置动态路由
通过配置好的 Server 服务的集群,再使用上lb
关键字,我们可以配置动态路由。如下:
uri: lb://MEMBER-SERVICE-PROVIDER # 注意是大写发服务器名name(大小写都行)
server:
port: 20000
spring:
application:
name: e-commerce-gateway
cloud:
# 配置 Spring Cloud Gateway 内容
gateway:
routes: # 配置路由,可以配置多个路由 List<RouteDefinition> routes
- id: member_route01 # 路由的id,程序员自己配置,要求唯一
# 将查询服务,配置为动态的服务(轮询)负载均衡
# 1. lb: 协议名, member-service-provider 注册到eureka server服务名(小写)
# 2. 默认情况下,负载均衡算法是轮询
uri: lb://MEMBER-SERVICE-PROVIDER # 注意是大写发服务器名name(大小写都行)
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
- Path=/member/get/**
# 配置: 第二个请求路径映射路由
- id: member_route02 # 路由的id,程序员自己配置,要求"唯一"
uri: lb://MEMBER-SERVICE-PROVIDER # 注意是大写发服务器名name(大小写都行)
# 配置(轮询负载均衡)动态调用服务器
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
# 这时如果客户端/浏览器 访问 gateway 的url http://localhost:20000/member/save
# 匹配Path成功 最终访问的url就是 ; http://localhost:10000/member/save 给对对应配置转发的10000服务处理了
- Path=/member/save
# 配置: 第三个以百度作为映射路由:
# 配置为,访问百度的网址,注意看这里,我们的 path 是 / ,也就是首页,不写任何的信息内容
- id: member_route03 # 路由的id,程序员自己配置,要求"唯一"
uri: http://www.baidu.com
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
- Path=/
server:
port: 20000
spring:
application:
name: e-commerce-gateway
cloud:
# 配置 Spring Cloud Gateway 内容
gateway:
routes: # 配置路由,可以配置多个路由 List<RouteDefinition> routes
- id: member_route01 # 路由的id,程序员自己配置,要求唯一
# 将查询服务,配置为动态的服务(轮询)负载均衡
# 1. lb: 协议名, member-service-provider 注册到eureka server服务名(小写)
# 2. 默认情况下,负载均衡算法是轮询
uri: lb://MEMBER-SERVICE-PROVIDER # 注意是大写发服务器名name(大小写都行)
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
- Path=/member/get/**
# 配置: 第二个请求路径映射路由
- id: member_route02 # 路由的id,程序员自己配置,要求"唯一"
uri: lb://MEMBER-SERVICE-PROVIDER # 注意是大写发服务器名name(大小写都行)
# 配置(轮询负载均衡)动态调用服务器
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
# 这时如果客户端/浏览器 访问 gateway 的url http://localhost:20000/member/save
# 匹配Path成功 最终访问的url就是 ; http://localhost:10000/member/save 给对对应配置转发的10000服务处理了
- Path=/member/save
# 配置: 第三个以百度作为映射路由:
# 配置为,访问百度的网址,注意看这里,我们的 path 是 / ,也就是首页,不写任何的信息内容
- id: member_route03 # 路由的id,程序员自己配置,要求"唯一"
uri: http://www.baidu.com
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
- Path=/
# 配置 Eureka-Client
eureka:
instance:
hostname: e-commerce-service
client:
register-with-eureka: true # 将自己注册到 Eureka-Server 注册中心当中
fetch-registry: true
service-url:
# 表示将自己注册到哪个 eureka-server
# 这里我们将本微服务注册到EurekaServer 集群,使用","逗号间隔
# 这里为了方便,使用 Eureka Server 的单个服务环境进行测试,不采用集群的方式
defaultZone: http://eureka9001.com:9001/eureka/
2.4 配置定义负载均衡算法
Spring Cloud Gateway 默认是负载均衡轮询 算法,同样的我们也可以配置自定义负载均衡
算法。
这里我们配置 RandomRule
负载均衡随机 算法。通过配置类的方式,进行配置。
package com.rainbowsea.springcloud.config;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RibbonRule {
// 配置注入自己的负载均衡算法
@Bean
public IRule myRibbonRule() {
// 这里返回的是 RandomRule ,当然小伙伴也可以自己指定
return new RandomRule();
}
}
运行测试:
2.5 注意事项和细节
-
在
yaml
当中配置 Spring Cloud Gateway ,需要特别特别特别注意**缩进空格层级
** 。缩进错误了,层级也就错误了,是以缩进的方式来表示层级关系的,层级错误了,就会导致配置错误,识别错误,而且这种错误比较不容易发现。所以需要特别注意上它。 -
配置好动态路由后 Gateway 会根据注册中心微服务名,为请求创建动态路由,实现动态路由功能,
-
使用的
lb
协议支持负载均衡-轮询 算法 -
配置自己的负载均衡算法,测试完毕恢复成原来的轮询算法。
3. Spring Cloud Gateway 组件当中的“Predicate(断言)”机制
一句话: Predicate 就是一组匹配规则,当请求匹配成功,就执行对应的 Route, 匹配失败,放弃 处理/转发。
Route Predicate Factories:https://docs.spring.io/spring-cloud-gateway/reference/spring-cloud-gateway/request-predicates-factories.html
官网解读:
- Spring Cloud Gateway 包括许多内置 Route Predicate 工厂,所有这些Predicate都与Http请求的不同
属性匹配,可以组合使用- Spring Cloud Gateway 创建 Route 对象时,使用 RoutePredicateFactory 创建 Predicate 对象,
Predicate 对象可以赋值给Route- 所有这些谓词 都匹配HTTP请求的不同属性 多种谓词工厂可以组合。
3.1 After Route Predicate
需求: 只有 2024-11-17 之后的请求才进行匹配/转发, 不满足该条件的,不处理。
spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://example.org
predicates:
- After=2017-01-20T17:42:47.789-07:00[America/Denver]
yaml
spring:
application:
name: e-commerce-gateway
cloud:
gateway:
routes: # 配置路由,可以配置多个路由 List<RouteDefinition> routes
- id: member_route01 # 路由的id,程序员自己配置,要求唯一
uri: lb://MEMBER-SERVICE-PROVIDER # 注意是大写发服务器名name(大小写都行)
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
- Path=/member/get/**
- After=2024-11-17T23:48:50.519+08:00[Asia/Shanghai] # 配置断言限制访问时间
特别说明:如何获取时间格式, 创建一个ZonedDateTime 测试类,来获取当前时间,再根据需要修改。ZonedDateTime 可以获取到对应上面的时间格式的。
package com.rianbowsea.springcloud.test; import java.time.ZonedDateTime; public class T2 { public static void main(String[] args) { ZonedDateTime now = ZonedDateTime.now(); // 2024-11-17T23:48:50.519+08:00[Asia/Shanghai] System.out.println(now); } }
server:
port: 20000
spring:
application:
name: e-commerce-gateway
cloud:
gateway:
routes: # 配置路由,可以配置多个路由 List<RouteDefinition> routes
- id: member_route01 # 路由的id,程序员自己配置,要求唯一
uri: lb://MEMBER-SERVICE-PROVIDER # 注意是大写发服务器名name(大小写都行)
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
- Path=/member/get/**
- After=2024-11-17T23:48:50.519+08:00[Asia/Shanghai] # 配置断言限制访问
- id: member_route02 # 路由的id,程序员自己配置,要求"唯一"
# uri: http://localhost:10000
# 配置(轮询负载均衡)动态调用服务器
uri: lb://MEMBER-SERVICE-PROVIDER # 注意是大写发服务器名name
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
# 这时如果客户端/浏览器 访问 gateway 的url http://localhost:20000/member/save
# 匹配Path成功 最终访问的url就是 ; http://localhost:10000/member/save 给对对应配置转发的10000服务处理了
- Path=/member/save
# 配置 Eureka-Client
eureka:
instance:
hostname: e-commerce-service
client:
register-with-eureka: true # 将自己注册到 Eureka-Server 注册中心当中
fetch-registry: true
service-url:
# 表示将自己注册到哪个 eureka-server
# 这里我们将本微服务注册到EurekaServer 集群,使用","逗号间隔
# 这里为了方便,使用 Eureka Server 的单个服务环境进行测试,不采用集群的方式
defaultZone: http://eureka9001.com:9001/eureka/
启动 e-commerce-eureka-server-9001
启动 member-service-provider-10000/10002
启动 e-commerce-gateway-20000
浏览器:(通过网关访问) http://localhost:20000/member/get/1
浏览器输入: http://localhost:20000/member/get/1
如果不满足这个时间段,则是返回, 404
错误。
3.2 Before Route Predicate
需求: 只有 2024-11-17 之前的请求才进行匹配/转发, 不满足该条件的,不处 理
yaml
spring:
cloud:
gateway:
routes:
- id: before_route
uri: https://example.org
predicates:
- Before=2017-01-20T17:42:47.789-07:00[America/Denver]
spring:
application:
name: e-commerce-gateway
cloud:
gateway:
routes: # 配置路由,可以配置多个路由 List<RouteDefinition> routes
- id: member_route01 # 路由的id,程序员自己配置,要求唯一
# gateway 最终访问的url是 url=url+Path
# 匹配后提供服务的路由地址:也可以是外网 http://www.baidu.com
# 这里我们匹配为一个 localhost:10000 服务即可
# 比如: 客户端/浏览器请求: url http://localhost:20000/member/get/1
# 如果根据Path匹配成功,最终访问的url/转发url就是 url=http://localhost:10000/member/get/1
# 如果匹配失败,则有 gateway 返回 404信息
# 疑问: 这里老师配置的 url 是固定的,在当前这种情况其实可以不是有 Eureka Server,
# 后面老师会使用灵活配置的方式,配置,就会使用 Eureka Server
# 注意:当这里我们仅仅配置了一个url 的时候,就只会将信息转发到这个10000服务端,为我们处理业务,
# 一个服务就没有(轮询)的负载均衡了
# uri: http://localhost:10000
# 将查询服务,配置为动态的服务(轮询)负载均衡
# 1. lb: 协议名, member-service-provider 注册到eureka server服务名(小写)
# 2. 默认情况下,负载均衡算法是轮询
uri: lb://MEMBER-SERVICE-PROVIDER # 注意是大写发服务器名name(大小写都行)
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
- Path=/member/get/**
# - After=2024-11-17T23:48:50.519+08:00[Asia/Shanghai] # 配置断言限制访问时间,之后
- Before=2024-11-17T23:48:50.519+08:00[Asia/Shanghai] # 配置断言限制访问时间,之前
server:
port: 20000
spring:
application:
name: e-commerce-gateway
cloud:
gateway:
routes: # 配置路由,可以配置多个路由 List<RouteDefinition> routes
- id: member_route01 # 路由的id,程序员自己配置,要求唯一
uri: lb://MEMBER-SERVICE-PROVIDER # 注意是大写发服务器名name(大小写都行)
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
- Path=/member/get/**
- Before=2024-11-17T23:48:50.519+08:00[Asia/Shanghai] # 配置断言限制访问时间,之前
- id: member_route02 # 路由的id,程序员自己配置,要求"唯一"
# uri: http://localhost:10000
# 配置(轮询负载均衡)动态调用服务器
uri: lb://MEMBER-SERVICE-PROVIDER # 注意是大写发服务器名name
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
# 这时如果客户端/浏览器 访问 gateway 的url http://localhost:20000/member/save
# 匹配Path成功 最终访问的url就是 ; http://localhost:10000/member/save 给对对应配置转发的10000服务处理了
- Path=/member/save
# 配置为,访问百度的网址,注意看这里,我们的 path 是 / ,也就是首页,不写任何的信息内容
# - id: member_route03 # 路由的id,程序员自己配置,要求"唯一"
# uri: http://www.baidu.com
# predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
# - Path=/
# 配置 Eureka-Client
eureka:
instance:
hostname: e-commerce-service
client:
register-with-eureka: true # 将自己注册到 Eureka-Server 注册中心当中
fetch-registry: true
service-url:
# 表示将自己注册到哪个 eureka-server
# 这里我们将本微服务注册到EurekaServer 集群,使用","逗号间隔
# 这里为了方便,使用 Eureka Server 的单个服务环境进行测试,不采用集群的方式
defaultZone: http://eureka9001.com:9001/eureka/
测试:
不满足该断言条件的:返回 404 错误
3.3 Between Route Predicate
需求: 只有 2024-11-17T23:48:50.519+08:00 和 2024-11-18T23:48:50 之间的请求才进行匹配/转 发, 不满足该条件的,不处理。
spring:
cloud:
gateway:
routes:
- id: between_route
uri: https://example.org
predicates:
- Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]
spring:
application:
name: e-commerce-gateway
cloud:
gateway:
routes: # 配置路由,可以配置多个路由 List<RouteDefinition> routes
- id: member_route01 # 路由的id,程序员自己配置,要求唯一
uri: lb://MEMBER-SERVICE-PROVIDER # 注意是大写发服务器名name(大小写都行)
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
- Path=/member/get/**
# - After=2024-11-17T23:48:50.519+08:00[Asia/Shanghai] # 配置断言限制访问时间,之后
# - Before=2024-11-17T23:48:50.519+08:00[Asia/Shanghai] # 配置断言限制访问时间,之前
- Between=2024-11-17T23:48:50.519+08:00[Asia/Shanghai], 2024-11-18T23:48:50.519+08:00[Asia/Shanghai]
运行测试:不满足断言条件的,返回 404 错误。
3.4 Cookie Route Predicate
需求: 请求带有 cookie 键: user 值: rainbowsea 才匹配/断言成功。
yaml
spring:
cloud:
gateway:
routes:
- id: cookie_route
uri: https://example.org
predicates:
- Cookie=chocolate, ch.p
# Cookie=key,value
# chocolate 是 cookie 名字 ;ch.p 是cookie 的值,是按照正则表达式来匹配的
spring:
application:
name: e-commerce-gateway
cloud:
gateway:
routes: # 配置路由,可以配置多个路由 List<RouteDefinition> routes
- id: member_route01 # 路由的id,程序员自己配置,要求唯一
uri: lb://MEMBER-SERVICE-PROVIDER # 注意是大写发服务器名name(大小写都行)
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
- Path=/member/get/**
# - After=2024-11-17T23:48:50.519+08:00[Asia/Shanghai] # 配置断言限制访问时间,之后
# - Before=2024-11-17T23:48:50.519+08:00[Asia/Shanghai] # 配置断言限制访问时间,之前
# - Between=2024-11-17T23:48:50.519+08:00[Asia/Shanghai], 2024-11-18T23:48:50.519+08:00[Asia/Shanghai]
- Cookie=user,hsp # 配置 Cookie 断言
server:
port: 20000
spring:
application:
name: e-commerce-gateway
cloud:
gateway:
routes: # 配置路由,可以配置多个路由 List<RouteDefinition> routes
- id: member_route01 # 路由的id,程序员自己配置,要求唯一
uri: lb://MEMBER-SERVICE-PROVIDER # 注意是大写发服务器名name(大小写都行)
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
- Path=/member/get/**
- Cookie=user,rainbowsea # 配置 Cookie 断言
- id: member_route02 # 路由的id,程序员自己配置,要求"唯一"
# uri: http://localhost:10000
# 配置(轮询负载均衡)动态调用服务器
uri: lb://MEMBER-SERVICE-PROVIDER # 注意是大写发服务器名name
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
# 这时如果客户端/浏览器 访问 gateway 的url http://localhost:20000/member/save
# 匹配Path成功 最终访问的url就是 ; http://localhost:10000/member/save 给对对应配置转发的10000服务处理了
- Path=/member/save
# 配置为,访问百度的网址,注意看这里,我们的 path 是 / ,也就是首页,不写任何的信息内容
# - id: member_route03 # 路由的id,程序员自己配置,要求"唯一"
# uri: http://www.baidu.com
# predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
# - Path=/
# 配置 Eureka-Client
eureka:
instance:
hostname: e-commerce-service
client:
register-with-eureka: true # 将自己注册到 Eureka-Server 注册中心当中
fetch-registry: true
service-url:
# 表示将自己注册到哪个 eureka-server
# 这里我们将本微服务注册到EurekaServer 集群,使用","逗号间隔
# 这里为了方便,使用 Eureka Server 的单个服务环境进行测试,不采用集群的方式
defaultZone: http://eureka9001.com:9001/eureka/
3.5 Header Route Predicate
需求: 请求头 Header 有 X-Request-Id, 并且值 hello 才匹配/断言成功
spring:
cloud:
gateway:
routes:
- id: header_route
uri: https://example.org
predicates:
- Header=X-Request-Id, \d+
# X-Request-Id 是 header 的名称, \d+ 是一个正则表达式
X-Request-Id 是 header 的名称, \d+ 是一个正则表达式
spring:
application:
name: e-commerce-gateway
cloud:
gateway:
routes: # 配置路由,可以配置多个路由 List<RouteDefinition> routes
- id: member_route01 # 路由的id,程序员自己配置,要求唯一
uri: lb://MEMBER-SERVICE-PROVIDER # 注意是大写发服务器名name(大小写都行)
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
- Path=/member/get/**
# - After=2024-11-17T23:48:50.519+08:00[Asia/Shanghai] # 配置断言限制访问时间,之后
# - Before=2024-11-17T23:48:50.519+08:00[Asia/Shanghai] # 配置断言限制访问时间,之前
# - Between=2024-11-17T23:48:50.519+08:00[Asia/Shanghai], 2024-11-18T23:48:50.519+08:00[Asia/Shanghai]
# - Cookie=user,hsp # 配置 Cookie 断言
- Header=X-Request-Id, hello
server:
port: 20000
spring:
application:
name: e-commerce-gateway
cloud:
gateway:
routes: # 配置路由,可以配置多个路由 List<RouteDefinition> routes
- id: member_route01 # 路由的id,程序员自己配置,要求唯一
uri: lb://MEMBER-SERVICE-PROVIDER # 注意是大写发服务器名name(大小写都行)
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
- Path=/member/get/**
- Header=X-Request-Id, hello
# - Host=**.rainbowsea.com,**.anotherhost.org
# -
# - Method=POST,GET
# - Query=email, [\w-]+@([a-zA-Z]+\.)+[a-zA-Z]+ # red是参数名;gree是值(支持正则表达式)
# - RemoteAddr=127.0.0.1
# filters:
# - AddRequestParameter=color, blue #过滤器工厂会在匹配的请求头加上一对请求头, 名称为 color 值为 blue
# - AddRequestParameter=age, 18 # 过滤器工厂会在匹配的请求头加上一对请求头,名称为 age 值为 18
- id: member_route02 # 路由的id,程序员自己配置,要求"唯一"
# uri: http://localhost:10000
# 配置(轮询负载均衡)动态调用服务器
uri: lb://MEMBER-SERVICE-PROVIDER # 注意是大写发服务器名name
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
# 这时如果客户端/浏览器 访问 gateway 的url http://localhost:20000/member/save
# 匹配Path成功 最终访问的url就是 ; http://localhost:10000/member/save 给对对应配置转发的10000服务处理了
- Path=/member/save
# 配置为,访问百度的网址,注意看这里,我们的 path 是 / ,也就是首页,不写任何的信息内容
# - id: member_route03 # 路由的id,程序员自己配置,要求"唯一"
# uri: http://www.baidu.com
# predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
# - Path=/
# 配置 Eureka-Client
eureka:
instance:
hostname: e-commerce-service
client:
register-with-eureka: true # 将自己注册到 Eureka-Server 注册中心当中
fetch-registry: true
service-url:
# 表示将自己注册到哪个 eureka-server
# 这里我们将本微服务注册到EurekaServer 集群,使用","逗号间隔
# 这里为了方便,使用 Eureka Server 的单个服务环境进行测试,不采用集群的方式
defaultZone: http://eureka9001.com:9001/eureka/
3.6 Host Route Predicate
需求: 请求 Host 是**.rainbowsea.** 才匹配/断言成功 比如 Host www.rainbowsea.com
spring:
cloud:
gateway:
routes:
- id: host_route
uri: https://example.org
predicates:
- Host=**.somehost.org,**.anotherhost.org
Host 可以有多个, 使用逗号间隔
spring:
application:
name: e-commerce-gateway
cloud:
gateway:
routes: # 配置路由,可以配置多个路由 List<RouteDefinition> routes
uri: lb://MEMBER-SERVICE-PROVIDER # 注意是大写发服务器名name(大小写都行)
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
- Path=/member/get/**
# - After=2024-11-17T23:48:50.519+08:00[Asia/Shanghai] # 配置断言限制访问时间,之后
# - Before=2024-11-17T23:48:50.519+08:00[Asia/Shanghai] # 配置断言限制访问时间,之前
# - Between=2024-11-17T23:48:50.519+08:00[Asia/Shanghai], 2024-11-18T23:48:50.519+08:00[Asia/Shanghai]
# - Cookie=user,hsp # 配置 Cookie 断言
# - Header=X-Request-Id, hello
- Host=**.rainbowsea.com,**.anotherhost.org
server:
port: 20000
spring:
application:
name: e-commerce-gateway
cloud:
gateway:
routes: # 配置路由,可以配置多个路由 List<RouteDefinition> routes
- id: member_route01 # 路由的id,程序员自己配置,要求唯一
uri: lb://MEMBER-SERVICE-PROVIDER # 注意是大写发服务器名name(大小写都行)
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
- Path=/member/get/**
- Host=**.rainbowsea.com,**.anotherhost.org
- id: member_route02 # 路由的id,程序员自己配置,要求"唯一"
# uri: http://localhost:10000
# 配置(轮询负载均衡)动态调用服务器
uri: lb://MEMBER-SERVICE-PROVIDER # 注意是大写发服务器名name
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
# 这时如果客户端/浏览器 访问 gateway 的url http://localhost:20000/member/save
# 匹配Path成功 最终访问的url就是 ; http://localhost:10000/member/save 给对对应配置转发的10000服务处理了
- Path=/member/save
# 配置为,访问百度的网址,注意看这里,我们的 path 是 / ,也就是首页,不写任何的信息内容
# - id: member_route03 # 路由的id,程序员自己配置,要求"唯一"
# uri: http://www.baidu.com
# predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
# - Path=/
# 配置 Eureka-Client
eureka:
instance:
hostname: e-commerce-service
client:
register-with-eureka: true # 将自己注册到 Eureka-Server 注册中心当中
fetch-registry: true
service-url:
# 表示将自己注册到哪个 eureka-server
# 这里我们将本微服务注册到EurekaServer 集群,使用","逗号间隔
# 这里为了方便,使用 Eureka Server 的单个服务环境进行测试,不采用集群的方式
defaultZone: http://eureka9001.com:9001/eureka/
3.7 Method Route Predicate
需求: 请求是 Get 方式才匹配/断言成功。
spring:
cloud:
gateway:
routes:
- id: method_route
uri: https://example.org
predicates:
- Method=GET,POST
spring:
application:
name: e-commerce-gateway
cloud:
gateway:
routes: # 配置路由,可以配置多个路由 List<RouteDefinition> routes
- id: member_route01 # 路由的id,程序员自己配置,要求唯一
uri: lb://MEMBER-SERVICE-PROVIDER # 注意是大写发服务器名name(大小写都行)
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
- Path=/member/get/**,/member/save
- Method=POST,GET
请求方式可以有多个 使用逗号间隔。
3.8 Path Route Predicate
Path Route Predicate: Path 可以有多个, 使用逗号间隔
server:
port: 20000
spring:
application:
name: e-commerce-gateway
cloud:
gateway:
routes: # 配置路由,可以配置多个路由 List<RouteDefinition> routes
- id: member_route01 # 路由的id,程序员自己配置,要求唯一
uri: lb://MEMBER-SERVICE-PROVIDER # 注意是大写发服务器名name(大小写都行)
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
- Path=/member/get/**,/member/save/**
3.9 Query Route Predicate
需求: 请求有参数 email ,并且满足电子邮件的基本格式, 才能匹配/断言成功
spring:
cloud:
gateway:
routes:
- id: query_route
uri: https://example.org
predicates:
- Query=red, gree.
# red 是参数名 gree. 是值 支持正则表达式.
red 是参数名 gree. 是值 支持正则表达式.
spring:
application:
name: e-commerce-gateway
cloud:
gateway:
routes: # 配置路由,可以配置多个路由 List<RouteDefinition> routes
- id: member_route01 # 路由的id,程序员自己配置,要求唯一
- Path=/member/get/**
- Query=email, [\w-]+@([a-zA-Z]+\.)+[a-zA-Z]+ # red是参数名;gree是值(支持正则表达式)
server:
port: 20000
spring:
application:
name: e-commerce-gateway
cloud:
gateway:
routes: # 配置路由,可以配置多个路由 List<RouteDefinition> routes
- id: member_route01 # 路由的id,程序员自己配置,要求唯一
uri: lb://MEMBER-SERVICE-PROVIDER # 注意是大写发服务器名name(大小写都行)
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
- Path=/member/get/**,/member/save/**
# - After=2024-11-17T23:48:50.519+08:00[Asia/Shanghai] # 配置断言限制访问时间,之后
# - Before=2024-11-17T23:48:50.519+08:00[Asia/Shanghai] # 配置断言限制访问时间,之前
# - Between=2024-11-17T23:48:50.519+08:00[Asia/Shanghai], 2024-11-18T23:48:50.519+08:00[Asia/Shanghai]
# - Cookie=user,rainbowsea # 配置 Cookie 断言
# - Header=X-Request-Id, hello
# - Host=**.rainbowsea.com,**.anotherhost.org
# -
# - Method=POST,GET
- Query=email, [\w-]+@([a-zA-Z]+\.)+[a-zA-Z]+ # red是参数名;gree是值(支持正则表达式)
# - RemoteAddr=127.0.0.1
# filters:
# - AddRequestParameter=color, blue #过滤器工厂会在匹配的请求头加上一对请求头, 名称为 color 值为 blue
# - AddRequestParameter=age, 18 # 过滤器工厂会在匹配的请求头加上一对请求头,名称为 age 值为 18
- id: member_route02 # 路由的id,程序员自己配置,要求"唯一"
# uri: http://localhost:10000
# 配置(轮询负载均衡)动态调用服务器
uri: lb://MEMBER-SERVICE-PROVIDER # 注意是大写发服务器名name
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
# 这时如果客户端/浏览器 访问 gateway 的url http://localhost:20000/member/save
# 匹配Path成功 最终访问的url就是 ; http://localhost:10000/member/save 给对对应配置转发的10000服务处理了
- Path=/member/save
# 配置为,访问百度的网址,注意看这里,我们的 path 是 / ,也就是首页,不写任何的信息内容
# - id: member_route03 # 路由的id,程序员自己配置,要求"唯一"
# uri: http://www.baidu.com
# predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
# - Path=/
# 配置 Eureka-Client
eureka:
instance:
hostname: e-commerce-service
client:
register-with-eureka: true # 将自己注册到 Eureka-Server 注册中心当中
fetch-registry: true
service-url:
# 表示将自己注册到哪个 eureka-server
# 这里我们将本微服务注册到EurekaServer 集群,使用","逗号间隔
# 这里为了方便,使用 Eureka Server 的单个服务环境进行测试,不采用集群的方式
defaultZone: http://eureka9001.com:9001/eureka/
3.10 RemoteAddr Route Predicate
需求: 请求的 IP 是 127.0.0.1, 才能匹配/断言成功
yaml
spring:
cloud:
gateway:
routes:
- id: remoteaddr_route
uri: https://example.org
predicates:
- RemoteAddr=192.168.1.1/24
spring:
application:
name: e-commerce-gateway
cloud:
gateway:
routes: # 配置路由,可以配置多个路由 List<RouteDefinition> routes
- id: member_route01 # 路由的id,程序员自己配置,要求唯一
uri: lb://MEMBER-SERVICE-PROVIDER # 注意是大写发服务器名name(大小写都行)
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
- Path=/member/get/**
- RemoteAddr=127.0.0.1
server:
port: 20000
spring:
application:
name: e-commerce-gateway
cloud:
gateway:
routes: # 配置路由,可以配置多个路由 List<RouteDefinition> routes
- id: member_route01 # 路由的id,程序员自己配置,要求唯一
uri: lb://MEMBER-SERVICE-PROVIDER # 注意是大写发服务器名name(大小写都行)
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
- Path=/member/get/**,/member/save/**
# - After=2024-11-17T23:48:50.519+08:00[Asia/Shanghai] # 配置断言限制访问时间,之后
# - Before=2024-11-17T23:48:50.519+08:00[Asia/Shanghai] # 配置断言限制访问时间,之前
# - Between=2024-11-17T23:48:50.519+08:00[Asia/Shanghai], 2024-11-18T23:48:50.519+08:00[Asia/Shanghai]
# - Cookie=user,rainbowsea # 配置 Cookie 断言
# - Header=X-Request-Id, hello
# - Host=**.rainbowsea.com,**.anotherhost.org
# -
# - Method=POST,GET
# - Query=email, [\w-]+@([a-zA-Z]+\.)+[a-zA-Z]+ # red是参数名;gree是值(支持正则表达式)
- RemoteAddr=127.0.0.1
# filters:
# - AddRequestParameter=color, blue #过滤器工厂会在匹配的请求头加上一对请求头, 名称为 color 值为 blue
# - AddRequestParameter=age, 18 # 过滤器工厂会在匹配的请求头加上一对请求头,名称为 age 值为 18
- id: member_route02 # 路由的id,程序员自己配置,要求"唯一"
# uri: http://localhost:10000
# 配置(轮询负载均衡)动态调用服务器
uri: lb://MEMBER-SERVICE-PROVIDER # 注意是大写发服务器名name
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
# 这时如果客户端/浏览器 访问 gateway 的url http://localhost:20000/member/save
# 匹配Path成功 最终访问的url就是 ; http://localhost:10000/member/save 给对对应配置转发的10000服务处理了
- Path=/member/save
# 配置为,访问百度的网址,注意看这里,我们的 path 是 / ,也就是首页,不写任何的信息内容
# - id: member_route03 # 路由的id,程序员自己配置,要求"唯一"
# uri: http://www.baidu.com
# predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
# - Path=/
# 配置 Eureka-Client
eureka:
instance:
hostname: e-commerce-service
client:
register-with-eureka: true # 将自己注册到 Eureka-Server 注册中心当中
fetch-registry: true
service-url:
# 表示将自己注册到哪个 eureka-server
# 这里我们将本微服务注册到EurekaServer 集群,使用","逗号间隔
# 这里为了方便,使用 Eureka Server 的单个服务环境进行测试,不采用集群的方式
defaultZone: http://eureka9001.com:9001/eureka/
4. Spring Cloud Gateway 组件当中的 “Filter(过滤器)” 机制
官方地址:https://docs.spring.io/spring-cloud-gateway/reference/spring-cloud-gateway/gatewayfilter-factories/addrequestheader-factory.html
- 一句话: 使用过滤器,可以在请求被路由前或者之后对请求进行处理。
- 你可以理解成,在对 Http请求断言匹配成功后,可以通过网关的过滤机制,对Http请求处理。
- 简单举例:
filters:
-AddRequestParameter=color,blue # 过滤器在匹配的请求头加上一对请求头,名称为color值为blue
,比如原来的http请求是:http://localhost:10000/member/get/1 ===过滤器处理
http://localhost:10000/member/get/1?color=blue
路由过滤器可用于修改进入的HTTP请求和返回的 HTTP 响应 ,Spring Cloud Gateway 内置了多种路由过滤器,他们都由GatewayFilter的工厂类来产生。
4.1 GatewayFilter 使用
开发直接使用 GatewayFilter 较少,一般是自定义过滤器
spring:
cloud:
gateway:
routes:
- id: add_request_header_route
uri: https://example.org
filters:
- AddRequestHeader=X-Request-red, blue
spring:
application:
name: e-commerce-gateway
cloud:
gateway:
routes: # 配置路由,可以配置多个路由 List<RouteDefinition> routes
- id: member_route01 # 路由的id,程序员自己配置,要求唯一
uri: lb://MEMBER-SERVICE-PROVIDER # 注意是大写发服务器名name(大小写都行)
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
- Path=/member/get/**
# - Path=/member/get/**,/member/save
# - After=2024-11-17T23:48:50.519+08:00[Asia/Shanghai] # 配置断言限制访问时间,之后
# - Before=2024-11-17T23:48:50.519+08:00[Asia/Shanghai] # 配置断言限制访问时间,之前
# - Between=2024-11-17T23:48:50.519+08:00[Asia/Shanghai], 2024-11-18T23:48:50.519+08:00[Asia/Shanghai]
# - Cookie=user,hsp # 配置 Cookie 断言
# - Header=X-Request-Id, hello
# - Host=**.rainbowsea.com,**.anotherhost.org
# -
# - Method=POST,GET
# - Query=email, [\w-]+@([a-zA-Z]+\.)+[a-zA-Z]+ # red是参数名;gree是值(支持正则表达式)
# - RemoteAddr=127.0.0.1
filters:
- AddRequestParameter=color, blue #过滤器工厂会在匹配的请求头加上一对请求头, 名称为 color 值为 blue
- AddRequestParameter=age, 18 # 过滤器工厂会在匹配的请求头加上一对请求头,名称为 age 值为 18
server:
port: 20000
spring:
application:
name: e-commerce-gateway
cloud:
gateway:
routes: # 配置路由,可以配置多个路由 List<RouteDefinition> routes
- id: member_route01 # 路由的id,程序员自己配置,要求唯一
uri: lb://MEMBER-SERVICE-PROVIDER # 注意是大写发服务器名name(大小写都行)
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
- Path=/member/get/**
filters:
- AddRequestParameter=color, blue #过滤器工厂会在匹配的请求头加上一对请求头, 名称为 color 值为 blue
- AddRequestParameter=age, 18 # 过滤器工厂会在匹配的请求头加上一对请求头,名称为 age 值为 18
- id: member_route02 # 路由的id,程序员自己配置,要求"唯一"
# uri: http://localhost:10000
# 配置(轮询负载均衡)动态调用服务器
uri: lb://MEMBER-SERVICE-PROVIDER # 注意是大写发服务器名name
predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
# 这时如果客户端/浏览器 访问 gateway 的url http://localhost:20000/member/save
# 匹配Path成功 最终访问的url就是 ; http://localhost:10000/member/save 给对对应配置转发的10000服务处理了
- Path=/member/save
# 配置为,访问百度的网址,注意看这里,我们的 path 是 / ,也就是首页,不写任何的信息内容
# - id: member_route03 # 路由的id,程序员自己配置,要求"唯一"
# uri: http://www.baidu.com
# predicates: # 断言,可以多种形式 # 断言为通过报 404 找不到异常
# - Path=/
# 配置 Eureka-Client
eureka:
instance:
hostname: e-commerce-service
client:
register-with-eureka: true # 将自己注册到 Eureka-Server 注册中心当中
fetch-registry: true
service-url:
# 表示将自己注册到哪个 eureka-server
# 这里我们将本微服务注册到EurekaServer 集群,使用","逗号间隔
# 这里为了方便,使用 Eureka Server 的单个服务环境进行测试,不采用集群的方式
defaultZone: http://eureka9001.com:9001/eureka/
/**
* 这里我们使用 url占位符 + @PathVariable
*
* @param id
* @return
*/
@GetMapping("/member/get/{id}")
public Result getMemberById(@PathVariable("id") Long id, HttpServletRequest request) {
Member member = memberService.queryMemberById(id);
String color = request.getParameter("color");
String age = request.getParameter("age");
// 模拟超时 ,这里暂停 5秒
/* try {
TimeUnit.SECONDS.sleep(5);
} catch (Exception e) {
e.printStackTrace();
}*/
// 使用 Result 把查询到的结果返回
if (member != null) {
return Result.success("查询会员成功 member-service-provider-10000 color" + color + "age" + age, member);
} else {
return Result.error("402", "ID" + id + "不存在 member-service-provider-10000 ");
}
}
运行测试:
4.2 自定义 GlobalFilter
自定义全局 GlobalFilter 过滤器。
如果请求参数 user=rainbowsea, pwd=123456 则放行, 否则不能通过验证
通过配置类的方式,配置自定义 GlobalFilter 过滤器 。
注意定义的 GlobalFilter 过滤器,要实现
implements GlobalFilter, Ordered
接口。同时重写其中的getOrder()
和filter(ServerWebExchange exchange, GatewayFilterChain chain)
方法。
package com.rainbowsea.springcloud.filter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component
public class CustomGateWayFilter implements GlobalFilter, Ordered {
// filter 是核心的方法,将我们的过滤的业务,写在该方法中
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 先获取到对应的参数值
// 比如:http://localhost:20000/member/get?user=rainbowsea&pwd123456
// 第一种方式获得:get("user")返回的是List集合,需要再get(0) 表明序列返回的是字符串
//String regStr = exchange.getRequest().getQueryParams().get("user").get(0);
String user = exchange.getRequest().getQueryParams().getFirst("user");
String pwd = exchange.getRequest().getQueryParams().getFirst("pwd");
if (!("rainbowsea".equals(user) && "123456".equals(pwd))) { // 如果不满足条件
System.out.println("非法用户");
// NOT_ACCEPTABLE 是 406 错误
// NOT_ACCEPTABLE(406, "Not Acceptable"),
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);// 回应
return exchange.getResponse().setComplete();
}
// 验证通过,放行 // 注意需要将前面我们再 application.yaml 当中配置的 filters 过滤器的前缀给去了,进行测试比较明显
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
}
运行测试:
5. 总结:
- Spring Cloud Gateway网关 的核心功能。
- Spring Cloud Gateway VS Zuul 的区别
- Spring Cloud Gateway 的基本原理
- Spring Cloud Gateway (How It Works 工作机制)
- Spring Cloud Gateway 的三大核心组件 Route(路由),Predicate(断言),Filter(过滤)
- Spring Cloud Gateway组件当中的“Routing(路由):一句话:路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为 true 则匹配该路由。
配置 Spring Cloud Gateway 的 Routing(路由)有两种方式:
- 第一种方式:通过
application.yaml
配置文件的的方式,配置Routing(路由) - 第二种方式:通过定义配置类的方式,配置Routing(路由)
- 配置动态路由和配置定义负载均衡算法。
- Spring Cloud Gateway组件当中的“Predicate(断言)”机制
一句话: Predicate 就是一组匹配规则,当请求匹配成功,就执行对应的 Route, 匹配失败,放弃 处理/转发。
简单的举例:比如配置路径为:-Path=/member/get/**
# 断言,路径相匹配的进行路由转发,如果Http请求的路径不匹配,则不进行路由转发。
断言无法通过,报404
错误
- Spring Cloud Gateway 组件当中的 “Filter(过滤器)” 机制 。
一句话:使用过滤器,可以在请求被路由前或者之后 对请求进行处理。
你可以理解成,在对HTTP请求断言匹配成功后,可以通过网关的过滤机制,对HTTP请求处理。
简单举例:
filters:
- AddRequestParameter=color,blue # 过滤器在匹配的请求头加上一对请求头,名称为color值为 blue,比 如 原 来 的 http 请 求 是 http://localhost:10000/member/get/1 == 过 滤 器 处 理 => http://localhost:10000/member/get/1?color=blue
自定义全局 GlobalFilter 过滤器。如果请求参数 user=rainbowsea, pwd=123456 则放行, 否则不能通过验证。
通过配置类的方式,配置自定义 GlobalFilter 过滤器 。
注意定义的 GlobalFilter 过滤器,要实现
implements GlobalFilter, Ordered
接口。同时重写其中的getOrder()
和filter(ServerWebExchange exchange, GatewayFilterChain chain)
方法。
6. 最后:
“在这个最后的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。感谢你们,我们总会在某个时刻再次相遇。”