接着上篇:
之前写了,使用nacos的注册和配置、OpenFeign的远程调用;这篇文章是关于Gateway的使用,通过这篇文章,你能在微服务中使用gateway网关,并能做一些简单的配置;
nacso: springboot3整合nacos实现注册中心和配置中心(详细入门)-CSDN博客
Openfeign: spring boot整合openfeign实现两个微服务之间的调用。-CSDN博客
1、首先来介绍一下gateway:
Gateway(网关)网络的关口。
是一种用于构建微服务架构中的统一访问入口的服务器。它充当了客户端和后端微服务之间的中介,负责请求的路由、转发、身份校验、过滤、转换和聚合等功能。
网关与各个微服务之间的关系:

网关的组成:通过路由(Route)、过滤器(Filter)和断言(Predicate)组成了一个完整的网关服务
gatewry
路由、谓词与过滤器组成
- 路由:id,uri
谓词:-Path、-Header -After 等等条件组成
过滤器:filter
gatewry常与nacos注册中心,loadBalancer负载均衡等一起使用
在之前项目的基础上,我们再来添加网关应用;
一个父项目,下面有三个子模块。父项目中进行依赖的管理和维护,有一个生产者模块(producer)、一个消费者模块(consumer),还有一个OpenFeign模块(api),专门用来进行微服务之间的调用。
2、再之前项目的基础上添加一个新模块(gateway):
并在这个模块中新引入一些依赖
org.springframework.cloud
spring-cloud-starter-gateway
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
org.springframework.cloud
spring-cloud-starter-loadbalancer
注意:引入了gateway依赖之后,就不用再引入web依赖了。不然两个依赖有冲突会报错的
主要原因是Spring Boot的自动装配机制。
Spring Cloud Gateway依赖包含了Spring WebFlux,它是基于响应式编程模型构建的非阻塞Web框架。而传统的Spring Web依赖(spring-boot-starter-web)是基于Servlet容器的阻塞式Web框架。
当同时引入Spring Cloud Gateway和spring-boot-starter-web依赖时,两者之间可能存在冲突,因为它们使用不同的Web框架和Servlet容器。
解决这个问题的方法是选择其中一种依赖,根据项目需求和开发模式进行选择:
-
如果你想使用Spring Cloud Gateway,那么可以移除spring-boot-starter-web依赖,只保留Spring Cloud Gateway相关的依赖。这样可以完全采用非阻塞的WebFlux编程模型。
-
如果你需要使用传统的Spring MVC编程模型,可以移除Spring Cloud Gateway的依赖,只保留spring-boot-starter-web依赖。这样可以使用基于Servlet容器的阻塞式Web框架。
需要注意的是,这两种方式是互斥的,不能同时使用。根据项目需求和开发模式选择适合的依赖,并确保版本兼容性,可以避免相关错误的发生。
3、在gateway模块中配置初始属性:
1、创建启动类
2、在yml文件中设置nacos的注册信息和gateway网关的路由:
server:
port: 8080
spring:
application:
name: gateway
cloud:
nacos:
discovery:
server-addr: 192.168.231.110:8848
gateway:
routes:
- id: consumer #路由规则id,自定义,唯一
uri: lb://consumer #路由目标的微服务,lb代表负载均衡
predicates: #路由断言,判断请求是否符合规则,符合则路由到目标
- Path= /consumer/** #以请求路径做判断,以/user开头的符合
- id: producer
uri: lb://producer
predicates:
- Path= /producer/**
先将gateway添加到nacos注册中心中,然后解释一下路由(routes)的一些参数
-
id:每个路由规则都需要一个唯一的id
来标识,它可以是任意字符串。id
主要用于在日志和监控中标识特定的路由。
-
uri:uri
表示目标服务的统一资源标识符(Uniform Resource Identifier),可以是HTTP、HTTPS或自定义协议等。你可以使用http://
或https://
开头指定目标服务的地址,并且可以包含相关的路径、查询参数、片段等信息。这里我们将gateway模块也放在了nacos中。因此这里可以直接写模块在nacos中的服务名称
-
predicates:predicates
用于匹配请求的条件,只有满足条件的请求才会被路由到对应的目标服务。你可以根据请求的URI、方法、头部等属性来定义条件,并使用逻辑运算符(如AND、OR、NOT)组合多个条件。在这里我们规定根据请求头来将相应的请求转发到特定的微服务;
4、将这三个模块都启动起来,然后来访问gateway模块的端口,看能不能转发到相应的模块:

请求producer模块的方法:发现我们访问的是8080gateway模块的端口,却能映射到producer模块

请求consumer 模块的方法:

Spring Cloud Gateway提供了12个基本的路由断言,用于匹配请求并将其路由到相应的微服务实例。这些基本的路由断言如下:
-
After: 匹配请求日期时间在指定时间之后的条件,例如:after=2022-01-01T00:00:00.000+08:00[Asia/Shanghai]。
-
Before: 匹配请求日期时间在指定时间之前的条件,例如:before=2022-01-01T00:00:00.000+08:00[Asia/Shanghai]。
-
Between: 匹配请求日期时间在两个指定时间之间的条件,例如:between=2022-01-01T00:00:00.000+08:00[Asia/Shanghai], 2022-12-31T23:59:59.999+08:00[Asia/Shanghai]。
-
Cookie: 匹配请求中携带指定Cookie的条件,例如:Cookie=name, value。
-
Header: 匹配请求中包含指定Header的条件,例如:Header=X-Request-Id, \d+。
-
Host: 匹配请求的Host头部信息的条件,例如:Host=**.example.com。
-
Method: 匹配请求的HTTP方法的条件,例如:Method=GET。
-
Path: 匹配请求的路径的条件,例如:Path=/foo/{segment}。
-
Query: 匹配请求的查询参数的条件,例如:Query=foo, ba?。
-
RemoteAddr: 匹配请求的远程地址的条件,例如:RemoteAddr=192.168.1.1/24。
-
Weight: 通过权重来匹配多个微服务实例的条件,例如:Weight=group1=4,group2=6。
-
XForwader Remote Addr: 基于请求的来源Ip做判断, 例如:-XForwaderRemoteAddr=192.168.231.110/80
相应的图片:

这些我之前使用了Path路径匹配。剩下的我就不一一演示了,感兴趣的可以自己演示;
4、网关(gateway)过滤器:
Spring Cloud Gateway的过滤器提供了一种强大的机制来对请求进行修改和处理。通过合理配置和编写自定义的过滤器,你可以实现各种功能,如鉴权、请求日志记录、限流等

Spring Cloud Gateway中的过滤器分为两种类型:全局过滤器和局部过滤器。
1、全局过滤器:全局过滤器会应用于所有的路由规则。你可以使用GlobalFilter
接口实现全局过滤器,该接口定义了一个名为filter
的方法,用于对请求进行处理。全局过滤器的顺序可以通过实现Ordered
接口来进行控制
有两种实现方式:
(1)、简单的在yml配置文件种进行实现:
如:我想在每个请求到来时,都在请求头上加入一个参数;
名字叫name,值为张三(name=张三)
gateway:
routes:
- id: consumer-test #路由规则id,自定义,唯一
uri: lb://consumer #路由目标的微服务,lb代表负载均衡
predicates: #路由断言,判断请求是否符合规则,符合则路由到目标
- Path= /consumer/** #以请求路径做判断,以/user开头的符合
- id: producer-test
uri: lb://producer
predicates:
- Path= /producer/**
default-filters: #全局过滤器
- AddRequestHeader=name,zhangsan
在服务中进行接收,看能不能接收到我们田间的参数(name=zhangsan)
在consumer模块中接收name属性:
@GetMapping("/test")
public String test(@RequestHeader(value = "name" ,required = false) String name){
System.out.println("name====>" +name);
System.out.println("来自服务提供者的数据");
return "consumer服务的test方法";
}
访问consumer/test方法,看能不能接收到name属性:

consumer模块结果:可以看到我们并没有在请求头种设置name属性,但是却接收到了name参数,这说明我们的过滤器生效了

(注意这种方式能传递数字,英文。但是不能传递中文,解析不了会出现乱码)
(2)、实现GlobalFilter接口的filter方法:
@Component
//@Order(0) //使用注解,或者实现Ordered接口
public class MyGlobalFilter implements GlobalFilter , Ordered {
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 获取请求
ServerHttpRequest request = exchange.getRequest();
URI uri = request.getURI();
System.out.println("请求的uri=========>"+uri);
//过滤器的业务处理
System.out.println("执行了业务处理");
// 放行
return chain.filter(exchange);
}
@Override
public int getOrder() {
// 过滤器执行顺序,数值越小,优先级越高
return 0;
}
}
执行的结果如下:可以看到执行了我们在全局过滤器种定义的逻辑:

2、局部过滤器:局部过滤器仅应用于特定的路由规则。你可以使用GatewayFilterFactory
接口和它的子类来实现局部过滤器
(1)、简单的在yml配置文件种进行实现:
gateway:
routes:
- id: consumer-test #路由规则id,自定义,唯一
uri: lb://consumer #路由目标的微服务,lb代表负载均衡
predicates: #路由断言,判断请求是否符合规则,符合则路由到目标
- Path= /consumer/** #以请求路径做判断,以/user开头的符合
- id: producer-test
uri: lb://producer
predicates:
- Path= /producer/**
filters:
- AddRequestHeader=name,zhangsan
这里的结果我就不再截图了,局部过滤器的生效范围只能在特定的路由;
(2)继承AbstractGatewayFilterFactory类,并重写GatewayFilter方法:
// 固定的GatewayFilterFactory类名后缀,方便配置使用
// 局部的过滤器配置完不能立即生效,还要再yml配置文件种添加filters过滤参数
// 这个参数为ProducerGatewayFilterFactory类名的前一部分:Producer
@Component
public class ProducerGatewayFilterFactory extends AbstractGatewayFilterFactory