文章目录
- 1.基本介绍
- 官方文档:https://springdoc.cn/spring-cloud-gateway/#gateway-starter
- 1.引出网关
- 2.使用网关服务架构图
- 3.Gateway网络拓扑图(背下来)
- 4.Gateway特性
- 5.Gateway核心组件
- 1.基本介绍
- 2.断言
- 3.过滤
- 6.Gateway工作机制
- 2.搭建Gateway微服务
- 1.引入Gateway架构
- 2.环境搭建
- 1.参考member-service-consumer-81 创建 e-commerce-gateway-20000 子模块
- 2.检查父子的pom.xml
- 1.父pom.xml
- 2.子pom.xml
- 3.pom.xml引入依赖
- 4.application.yml 配置gateway(这里的eureka还没有用到只是先配置一下)
- 5.编写启动类
- 6.依次启动9001,20000,10001模块进行测试
- 1.9001报错连接不上9002
- 2.20000Gateway正常启动
- 3.10001报错,连接9002被拒绝
- 4.输入http://eureka9001.com:9001/查看注册中心状态,成功注册20000, 10001!
- 5.postman测试
- 7.修改application.yml增加Gateway路由,访问到/member/save
- 8.postman测试
- 3.配置类注入Gateway(了解)
- 1.com/sun/springcloud/config/GatewayRoutesConfig.java
- 2.postman测试
- 4.动态路由
- 1.需求分析
- 2.动态路由配置
- 3.启动服务
- 4.postman测试
- 1.第一次
- 2.第二次,可以看出负载均衡算法默认是轮询
- 5.配置负载均衡算法
- 1.com/sun/springcloud/config/RibbonRule.java 配置类直接注入负载均衡算法的对象即可
- 2.重启服务进行测试
- 1.查看注册中心
- 2.postman向gateway发送几次请求
- 1.第一次
- 2.第二次,可以发现两次一样,不再是轮询算法
- 3.恢复轮询算法,注销掉刚才的配置类
- 6.Gateway 细节说明
- 1.关于predicates: - Path=/member/save中的`/`
- 2.关于uri: lb://member-service-provider服务发现的内容
- 3.Gateway执行流程
- 1.断言
- 2.服务发现
- 3.路径拼接
- 4.远程调用
- 6.Predicate(断言)
- 1.基本介绍
- 2.After Route Predicate 某个时间之后发送请求
- 1.需求分析
- 2.代码获取Gateway格式的时间
- 3.Gateway格式的时间
- 4.或者直接从官网获取这个Gateway格式的时间
- 5.应用实例
- 6.启动服务发送请求
- 3.Before Route Predicate 某个时间之前发送请求
- 1.需求分析
- 2.应用实例
- 3.postman发送请求
- 4.Between Route Predicate 两个时间之间发送请求
- 1.需求分析
- 2.应用实例
- 3.postman发送请求
- 5.Cookie Route Predicate 携带某个Cookie的请求
- 1.需求分析
- 2.应用实例
- 3.postman发送请求并设置cookie
- 1.携带cookie
- 2.不携带cookie
- 6.Header Route Predicate 携带某个Header属性的请求
- 1.需求分析
- 2.应用实例
- 3.postman请求Header携带参数
- 7.Host Route Predicate 指定主机发送的请求
- 1.需求分析
- 2.应用实例
- 3.postman请求修改host
- 8.Method Route Predicate 指定请求方式的请求
- 1.应用实例
- 2.postman测试
- 9.Path Route Predicate 指定路径的请求
- 应用实例
- 10.Query Route Predicate 参数满足指定条件的请求
- 1.需求分析
- 2.应用实例
- 3.postman测试
- 11.RemoteAddr Route Predicate 指定范围的ip客户端发送的请求
- 1.需求分析
- 2.应用实例
- 3.postman测试
- 12.weight Route Predicate 根据权重进行断言
- 7.过滤器
- 1.基本介绍
- 1.功能
- 2.工作流程
- 2.自定义过滤器
- 1.需求分析
- 2.代码实现 com/sun/springcloud/filter/CustomerGateWayFilter.java
- 3.postman测试
1.基本介绍
官方文档:https://springdoc.cn/spring-cloud-gateway/#gateway-starter
1.引出网关
2.使用网关服务架构图
3.Gateway网络拓扑图(背下来)
4.Gateway特性
5.Gateway核心组件
1.基本介绍
2.断言
3.过滤
6.Gateway工作机制
2.搭建Gateway微服务
1.引入Gateway架构
2.环境搭建
1.参考member-service-consumer-81 创建 e-commerce-gateway-20000 子模块
2.检查父子的pom.xml
1.父pom.xml
2.子pom.xml
3.pom.xml引入依赖
<dependencies>
<!--gateway不需要web-starter!-->
<!--<!– springboot web starter 用来监听端口–>-->
<!--<dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-web</artifactId>-->
<!-- <!– 如果在子工程/模块指定了 version,则以指定为准 –>-->
<!--</dependency>-->
<!--<dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-actuator</artifactId>-->
<!--</dependency>-->
<!-- 引入 cloud gateway -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- 引入eureka的客户端场景启动器 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<!-- 使用版本仲裁 -->
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 公共模块的jar包 -->
<dependency>
<groupId>org.example</groupId>
<artifactId>e_commerce_center-common-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
4.application.yml 配置gateway(这里的eureka还没有用到只是先配置一下)
server:
port: 20000
spring:
application:
name: e-commerce-gateway
cloud:
gateway:
routes: # 配置路由, List<RouteDefinition> routes,是集合类型
- id: member_route01 # 路由id,唯一即可
uri: http://localhost:10001 # 断言匹配成功后将这个与/member/get/**拼接
predicates:
- Path=/member/get/** # 断言匹配成功后的完整路径是http://localhost:10001/member/get/**
# 配置eureka,作为客户端,有服务注册和服务发现功能
eureka:
instance:
hostname: e-commerce-service
client:
register-with-eureka: true # 将自己注册到eureka服务
fetch-registry: true # 发现服务功能,如果是集群,必须要能发现服务才能配合ribben进行负载均衡
service-url:
defaultZone: http://eureka9001.com:9001/eureka/
5.编写启动类
package com.sun.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* @author 孙显圣
* @version 1.0
*/
@SpringBootApplication
@EnableEurekaClient
public class GateWayApplication20000 {
public static void main(String[] args) {
SpringApplication.run(GateWayApplication20000.class, args);
}
}
6.依次启动9001,20000,10001模块进行测试
1.9001报错连接不上9002
- 9002是eureka的一个server,与这个9001互相注册
- 而9002并没有开启,所以连接不上是正常的
2.20000Gateway正常启动
3.10001报错,连接9002被拒绝
- 10001是微服务集群中的一个服务,它注册到了9001和9002的server
- 9002没开,所以连接被拒绝,没问题
4.输入http://eureka9001.com:9001/查看注册中心状态,成功注册20000, 10001!
5.postman测试
路径匹配的情况
路径不匹配的情况,Gateway直接返回404
7.修改application.yml增加Gateway路由,访问到/member/save
server:
port: 20000
spring:
application:
name: e-commerce-gateway
cloud:
gateway:
routes: # 配置路由, List<RouteDefinition> routes,是集合类型
- id: member_route01 # 路由id,唯一即可
uri: http://localhost:10001 # 断言匹配成功后将这个与/member/get/**拼接
predicates:
- Path=/member/get/** # 断言匹配成功后的完整路径是http://localhost:10001/member/get/**
- id: member_route02 # 路由id,唯一即可
uri: http://localhost:10001 # 断言匹配成功后将这个与/member/save拼接
predicates:
- Path=/member/save # 断言匹配成功后的完整路径是http://localhost:10001//member/save
# 配置eureka,作为客户端,有服务注册和服务发现功能
eureka:
instance:
hostname: e-commerce-service
client:
register-with-eureka: true # 将自己注册到eureka服务
fetch-registry: true # 发现服务功能,如果是集群,必须要能发现服务才能配合ribben进行负载均衡
service-url:
defaultZone: http://eureka9001.com:9001/eureka/
8.postman测试
3.配置类注入Gateway(了解)
1.com/sun/springcloud/config/GatewayRoutesConfig.java
package com.sun.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;
/**
* Description:
*
* @Author sun
* @Create 2024/3/26 11:36
* @Version 1.0
*/
@Configuration
public class GatewayRoutesConfig {
@Bean
public RouteLocator routeLocator(RouteLocatorBuilder routeLocatorBuilder) {
RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
// 这里使用了Lambda表达式,理解为规定写法即可
return routes.route("member_route04",
r -> r.path("/member/get/**").uri("http://localhost:10001")).build();
}
}
2.postman测试
4.动态路由
1.需求分析
2.动态路由配置
server:
port: 20000
spring:
application:
name: e-commerce-gateway
cloud:
gateway:
routes: # 配置路由, List<RouteDefinition> routes,是集合类型
- id: member_route01 # 路由id,唯一即可
uri: lb://member-service-provider # 断言匹配成功后将这个与/member/get/**拼接,这里的lb是负载均衡的协议,服务名需要小写
predicates:
- Path=/member/get/** # 断言匹配成功后的完整路径是http://localhost:10001/member/get/**
- id: member_route02 # 路由id,唯一即可
uri: lb://member-service-provider # 断言匹配成功后将这个与/member/save拼接,,这里的lb是负载均衡的协议,,服务名需要小写
predicates:
- Path=/member/save # 断言匹配成功后的完整路径是http://localhost:10001//member/save
discovery:
locator:
enabled: true # 启用服务发现,不配置可能也不影响
# 配置eureka,作为客户端,有服务注册和服务发现功能
eureka:
# instance:
# hostname: e-commerce-service
client:
register-with-eureka: true # 将自己注册到eureka服务
fetch-registry: true # 发现服务功能,如果是集群,必须要能发现服务才能配合ribben进行负载均衡
service-url:
defaultZone: http://eureka9001.com:9001/eureka/
3.启动服务
4.postman测试
1.第一次
2.第二次,可以看出负载均衡算法默认是轮询
5.配置负载均衡算法
1.com/sun/springcloud/config/RibbonRule.java 配置类直接注入负载均衡算法的对象即可
package com.sun.springcloud.config;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Description: 配置自己的负载均衡算法,这里使用的随机算法
*
* @Author sun
* @Create 2024/3/26 14:31
* @Version 1.0
*/
@Configuration
public class RibbonRule {
@Bean
public IRule myRibbonRule() {
return new RandomRule();
}
}
2.重启服务进行测试
1.查看注册中心
2.postman向gateway发送几次请求
1.第一次
2.第二次,可以发现两次一样,不再是轮询算法
3.恢复轮询算法,注销掉刚才的配置类
6.Gateway 细节说明
1.关于predicates: - Path=/member/save中的/
这里的/
指的是http://ip + 端口/上下文路径/
2.关于uri: lb://member-service-provider服务发现的内容
这里通过注册中心发现的是微服务集群中对应服务的http://ip+端口/上下文路径(如果配置了的话)
3.Gateway执行流程
1.断言
对请求url进行断言
2.服务发现
如果通过断言,则从注册中心进行服务发现,并通过负载均衡算法得到指定服务的http://ip+端口/上下文路径(如果配置了的话)
3.路径拼接
将得到的http://ip+端口/上下文路径(如果配置了的话)
与进行断言的路径拼接
4.远程调用
通过拼接后的路径完成远程调用
6.Predicate(断言)
1.基本介绍
2.After Route Predicate 某个时间之后发送请求
1.需求分析
2.代码获取Gateway格式的时间
package com.sun.springcloud;
import java.time.ZonedDateTime;
/**
* Description:
*
* @Author sun
* @Create 2024/3/26 15:10
* @Version 1.0
*/
public class T2 {
public static void main(String[] args) {
ZonedDateTime now = ZonedDateTime.now();
System.out.println(now);
}
}
3.Gateway格式的时间
2024-03-26T15:12:23.371+08:00[Asia/Shanghai]
4.或者直接从官网获取这个Gateway格式的时间
5.应用实例
predicates:
- Path=/member/get/**
- After=2025-01-20T17:42:47.789+08:00[Asia/Shanghai] # 断言条件:在2025年1月20日下午5点42之后发送的请求
6.启动服务发送请求
3.Before Route Predicate 某个时间之前发送请求
1.需求分析
2.应用实例
predicates:
- Path=/member/get/**
- Before=2025-01-20T17:42:47.789-07:00[America/Denver] # 断言条件:2025年1月20日之前(这里是美国时间)
3.postman发送请求
4.Between Route Predicate 两个时间之间发送请求
1.需求分析
2.应用实例
predicates:
- Path=/member/get/**
- Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2025-01-21T17:42:47.789-07:00[America/Denver] # 断言条件,在2017年1月20日到2025年1月21日之间
3.postman发送请求
5.Cookie Route Predicate 携带某个Cookie的请求
1.需求分析
2.应用实例
predicates:
- Path=/member/get/**
- Cookie=user, sun # 断言条件,有cookie名为user,值为sun
3.postman发送请求并设置cookie
1.携带cookie
2.不携带cookie
6.Header Route Predicate 携带某个Header属性的请求
1.需求分析
2.应用实例
predicates:
- Path=/member/get/**
- Header=X-Request-Id, hello # 断言条件,Header中有X-Request-Id属性,值为hello
3.postman请求Header携带参数
7.Host Route Predicate 指定主机发送的请求
1.需求分析
2.应用实例
predicates:
- Path=/member/get/**
- Host=**.sunxiansheng.com,**.anotherhost.org # 断言条件:任意前缀的sunxiansheng.com和anotherhost.org的host
3.postman请求修改host
8.Method Route Predicate 指定请求方式的请求
1.应用实例
predicates:
- Path=/member/get/**
- Method=GET,POST # 断言条件:请求方式为GET和POST
2.postman测试
9.Path Route Predicate 指定路径的请求
应用实例
predicates:
- Path=/member/get/**, /member/get/save # 断言条件:路径为/member/get/**或者/member/get/save,其中的/是本服务的http://ip+端口/上下文路径/
10.Query Route Predicate 参数满足指定条件的请求
1.需求分析
2.应用实例
predicates:
- Path=/member/get/**
- Query=email, [\w-]+@([a-zA-Z]+\.)+[a-zA-Z]+ # 断言条件:请求携带参数为email,值要满足邮箱的格式
3.postman测试
11.RemoteAddr Route Predicate 指定范围的ip客户端发送的请求
1.需求分析
2.应用实例
predicates:
- Path=/member/get/**
- RemoteAddr=127.0.0.1 # 断言条件:客户端的ip只能是本机
3.postman测试
12.weight Route Predicate 根据权重进行断言
7.过滤器
1.基本介绍
1.功能
2.工作流程
- 简单来说就是在远程调用之前和远程调用之后可以进行过滤
- 过滤器链跟javaweb的过滤器一样
- 原生的过滤器使用的并不多,更多的是使用自定义的过滤器
2.自定义过滤器
1.需求分析
2.代码实现 com/sun/springcloud/filter/CustomerGateWayFilter.java
package com.sun.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;
/**
* Description: 编写全局过滤器
*
* @Author sun
* @Create 2024/3/26 18:50
* @Version 1.0
*/
@Component
public class CustomerGateWayFilter implements GlobalFilter, Ordered {
/**
* 在远程调用之前判断请求的参数user是否等于sun,pwd是否等于666
*
* @param exchange the current server exchange
* @param chain provides a way to delegate to the next filter
* @return
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("CustomerGateWayFilter被执行");
// 获取请求的参数,由于使用get方法返回的是一个list所以需要get(0)
String user = exchange.getRequest().getQueryParams().get("user").get(0);
// 使用getFirst相当于获取了请求参数名为pwd的第一个元素
String pwd = exchange.getRequest().getQueryParams().getFirst("pwd");
// 不满足要求就设置状态码之后直接返回
if (!("sun".equals(user) && "666".equals(pwd))) {
System.out.println("非法用户");
// 设置响应的状态码
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
// 返回
return exchange.getResponse().setComplete();
}
System.out.println("放行");
// 满足要求就放行
return chain.filter(exchange);
}
/**
* 根据返回的值来决定过滤器调用的顺序,数字越小则优先级越高
*
* @return
*/
@Override
public int getOrder() {
return 0;
}
}
3.postman测试
2