09.Gateway新一代网关

打印 上一主题 下一主题

主题 903|帖子 903|积分 2709

1.概述

1.1 是什么

1.1.1 官网

https://docs.spring.io/spring-cloud-gateway/reference/
1.1.2 体系定位

Cloud百口桶中有个很重要的组件就是网关,在1.x版本中都是采用的Zuul网关;但在2.x版本中,zuul的升级一直跳票,SpringCloud最后自己研发了一个网关SpringCloud Gateway替代Zuul。一句话:gateway是原zuul1.x版的替代。

1.2 项目中的网关的定位


1.3 能干吗

反向署理,鉴权,流量控制,熔断,日志控制等。
1.4 总结

Spring Cloud Gateway组件的核心是一系列的过滤器,通过这些过滤器可以将客户端发送的请求转发(路由)到对应的微服务。 Spring Cloud Gateway是加在整个微服务最前沿的防火墙和署理器,隐藏微服务结点IP端口信息,从而加强安全保护。Spring Cloud Gateway本身也是一个微服务,需要注册进服务注册中心。

2.Gateway三大核心

2.1 概述


2.2 Route(路由)

路由是构建网关的基本模块,由ID,目标URI,一系列的断言和过滤器构成,断言为true则匹配该路由。
2.3 Predicate(断言)

断言参考的是Java8的java.util.function.Predicate开发职员可以匹配HTTP请求中的内容(请求头或请求参数),请求符合断言,进行路由。
2.4 Filter(过滤)

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

http请求,到网关后,会先匹配是否有这个路由,有则进行断言,成功则经过过滤,转发到对应的微服务实例,进行后续的业务处置处罚。不存在请求路由,或断言失败都无法,进行请求转发。
3.Gateway工作流程


客户端向 Spring Cloud Gateway 发出请求。然后在 Gateway Handler Mapping 中找到与请求相匹配的路由,将其发送到 Gateway Web Handler。Handler 再通过指定的过滤器链来将请求发送到我们现实的服务执行业务逻辑,然后返回。
过滤器之间用虚线分开是因为过滤器可能会在发送署理请求之前(Pre)或之后(Post)执行业务逻辑。
在“pre”类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等;
在“post”类型的过滤器中可以做相应内容、相应头的修改,日志的输出,流量监控等有着非常重要的作用。
核心逻辑,路由转发 + 断言判断 + 执行过滤器链
4.入门配置

4.1 建module

cloud-gateway9527
4.2 改pom

一般Spring官网对于该组件的说明文档,都会有标识,该组件的maven坐标。
To include Spring Cloud Gateway in your project, use the starter with a group ID of org.springframework.cloud and an artifact ID of spring-cloud-starter-gateway. See the Spring Cloud Project page for details on setting up your build system with the current Spring Cloud Release Train.
  1. <dependency>
  2.     <groupId>org.springframework.cloud</groupId>
  3.     <artifactId>spring-cloud-starter-gateway</artifactId>
  4. </dependency>
  5. <dependency>
  6.     <groupId>org.springframework.cloud</groupId>
  7.     <artifactId>spring-cloud-starter-consul-discovery</artifactId>
  8. </dependency>
  9. <dependency>
  10.     <groupId>org.springframework.boot</groupId>
  11.     <artifactId>spring-boot-starter-actuator</artifactId>
  12. </dependency>
复制代码
4.3 YML
  1. server:
  2.   port: 9527
  3. spring:
  4.   application:
  5.     name: cloud-gateway #以微服务注册进consul或nacos服务列表内
  6.   cloud:
  7.     consul: #配置consul地址
  8.       host: localhost
  9.       port: 8500
  10.       discovery:
  11.         prefer-ip-address: true
  12.         service-name: ${spring.application.name}
复制代码
4.4 主启动
  1. import org.springframework.boot.autoconfigure.SpringBootApplication;
  2. import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
  3. @SpringBootApplication
  4. @EnableDiscoveryClient
  5. public class Main9527 {
  6.     public static void main(String[] args) {
  7.         SpringApplication.run(Main9527.class, args);
  8.     }
  9. }
复制代码
4.5 业务类

无,网关无任何业务代码。
4.6 启动

启动consul和gateway,会发现,在Consul(http://localhost:8500)中有,cloud-gateway实例。
5.网关如何做路由映射

5.1 诉求

不希望暴露8001端口,希望在8001真正的支付微服务表面套一层9527网关。
5.2 8001服务,新建PayGateWayController
  1. @RestController
  2. public class PayGateWayController
  3. {
  4.     @Resource
  5.     PayService payService;
  6.     @GetMapping(value = "/pay/gateway/get/{id}")
  7.     public ResultData<Pay> getById(@PathVariable("id") Integer id)
  8.     {
  9.         Pay pay = payService.getById(id);
  10.         return ResultData.success(pay);
  11.     }
  12.     @GetMapping(value = "/pay/gateway/info")
  13.     public ResultData<String> getGatewayInfo()
  14.     {
  15.         return ResultData.success("gateway info test:"+ IdUtil.simpleUUID());
  16.     }
  17. }
复制代码
5.3 启动8001,测试


5.4 cloud-gateway新增YML配置
  1. server:
  2.   port: 9527
  3. spring:
  4.   application:
  5.     name: cloud-gateway #以微服务注册进consul或nacos服务列表内
  6.   cloud:
  7.     consul: #配置consul地址
  8.       host: localhost
  9.       port: 8500
  10.       discovery:
  11.         prefer-ip-address: true
  12.         service-name: ${spring.application.name}    #以下为新增内容        gateway:      routes:        - id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,发起配合服务名          uri: http://localhost:8001                #匹配后提供服务的路由地点          predicates:            - Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由        - id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,发起配合服务名          uri: http://localhost:8001                #匹配后提供服务的路由地点          predicates:            - Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由
复制代码
5.5 重启9527

启动consul,8001,Gateway9527。
访问说明
添加网关前http://localhost:8001/pay/gateway/get/1
添加网关后http://localhost:9527/pay/gateway/get/1
隐真示假
  1.     gateway:
  2.       routes:
  3.       #映射到真实的微服务的ip和端口
  4.         - id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
  5.           uri: http://localhost:8001                #匹配后提供服务的路由地址
  6.           predicates:
  7.             - Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由
  8.             #映射到真实的微服务的ip和端口
  9.         - id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
  10.           uri: http://localhost:8001                #匹配后提供服务的路由地址
  11.           predicates:
  12.             - Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由
复制代码
证实,在8001支付微服务前在Gateway成功。但是注意这是,从外部访问时会走网关。
5.6 启动80订单微服务测试

5.6.1 修改cloud-api-commons的PayFeignApi接口
  1.     /**
  2.      * GateWay进行网关测试案例01
  3.      * @param id
  4.      * @return
  5.      */
  6.     @GetMapping(value = "/pay/gateway/get/{id}")
  7.     ResultData getById(@PathVariable("id") Integer id);
  8.     /**
  9.      * GateWay进行网关测试案例02
  10.      * @return
  11.      */
  12.     @GetMapping(value = "/pay/gateway/info")
  13.     ResultData<String> getGatewayInfo();
复制代码
5.6.2 修改cloud-comsumer-feign-order80模块

新增OrderGateWayController
  1. package com.atguigu.cloud.controller;
  2. import com.atguigu.cloud.apis.PayFeignApi;
  3. import com.atguigu.cloud.resp.ResultData;
  4. import jakarta.annotation.Resource;
  5. import org.springframework.web.bind.annotation.GetMapping;
  6. import org.springframework.web.bind.annotation.PathVariable;
  7. import org.springframework.web.bind.annotation.RestController;
  8. @RestController
  9. public class OrderGateWayController
  10. {
  11.     @Resource
  12.     private PayFeignApi payFeignApi;
  13.     @GetMapping(value = "/feign/pay/gateway/get/{id}")
  14.     public ResultData getById(@PathVariable("id") Integer id)
  15.     {
  16.         return payFeignApi.getById(id);
  17.     }
  18.     @GetMapping(value = "/feign/pay/gateway/info")
  19.     public ResultData<String> getGatewayInfo()
  20.     {
  21.         return payFeignApi.getGatewayInfo();
  22.     }
  23. }
复制代码
5.6.3 启动cloud-comsumer-feign-order80

访问http://localhost:8080/feign/pay/gateway/get/1
测试发现,gateway启动与否,都能获取到数据。
原因, 是因为PayFeignApi,配置的直接访问的8001的实例。不会走网关。因为80模块,是在服务体系的内部调用内部的微服务,不需要再走网关,多次一举,网关是对外部请求的一种分发和限定。也可以将其改成cloud-gateway服务,来测试网关结果,略。
  1. @FeignClient(value = "cloud-payment-service")
  2. public interface PayFeignApi {
  3.     ...
  4. }
复制代码
5.7 存在题目

上述yml配置,路由的地点,是写死的,其他服务一改端标语,配置失效了。
6.Gateway高级特性

6.1 Route以微服务名动态获取服务URI

6.1.1 存在题目

见上述5.7。
6.1.2 办理方式
  1. server:
  2.   port: 9527
  3. spring:
  4.   application:
  5.     name: cloud-gateway #以微服务注册进consul或nacos服务列表内
  6.   cloud:
  7.     consul: #配置consul地址
  8.       host: localhost
  9.       port: 8500
  10.       discovery:
  11.         prefer-ip-address: true
  12.         service-name: ${spring.application.name}    gateway:      routes:        - id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,发起配合服务名          #uri: http://localhost:8001                #匹配后提供服务的路由地点          uri: lb://cloud-payment-service          predicates:            - Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由        - id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,发起配合服务名          #uri: http://localhost:8001                #匹配后提供服务的路由地点          uri: lb://cloud-payment-service          predicates:            - Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由
复制代码
6.1.3测试

测试,cloud-payment-service服务,修改端标语,都可以访问成功。
6.2 Predicate(断言)

6.2.1 是什么

官网
https://docs.spring.io/spring-cloud-gateway/reference/spring-cloud-gateway/request-predicates-factories.html

Spring Cloud Gateway将路由匹配作为Spring WebFlux HandlerMapping底子架构的一部分。
Spring Cloud Gateway内置许多Route Predicate工厂。所有这些Predicate都与HTTP请求的不同属性匹配。多个Route Predicate工厂可以进行组合。
Spring Cloud Gateway创建Route对象时,使用RouterPredicateFactory创建Predicate对象,该对象赋给Route。Spring Cloud Gateway包含许多内置的Route Predicate Factories。所有这些谓词都匹配HTTP请求的不同属性,多种谓词工厂可以组合,并通过逻辑and。
6.3 启动gateway检察日志


6.4 整体架构


6.5 常用的内置Route Predicate

6.5.1 配置语法总体概述


6.5.2  Shortcut Configuration


6.5.3  Fully Expanded Arguments


6.5.4 测试地点

http://localhost:9527/pay/gateway/get/1
6.5.5 AfterRoutePredicate使用

官网例子

注意,After=背面跟的是ZonedDateTime类生成的时间字符串,需要ZonedDateTime生成。
  1. public class ZonedDateTimeDemo{
  2.     public static void main(String[] args){
  3.             ZonedDateTime zdt = ZonedDateTime.now(); // 默认时区
  4.                 System.out.println(zdt);
  5.     }
  6. }
复制代码
现实配置
  1. server:
  2.   port: 9527
  3. spring:
  4.   application:
  5.     name: cloud-gateway #以微服务注册进consul或nacos服务列表内
  6.   cloud:
  7.     consul: #配置consul地址
  8.       host: localhost
  9.       port: 8500
  10.       discovery:
  11.         prefer-ip-address: true
  12.         service-name: ${spring.application.name}    gateway:      routes:        - id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,发起配合服务名          #uri: http://localhost:8001                #匹配后提供服务的路由地点          uri: lb://cloud-payment-service          predicates:            - Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由            - After=2024-10-29T21:06:17.219789300+08:00[Asia/Shanghai] #在指定时间之后        - id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,发起配合服务名          #uri: http://localhost:8001                #匹配后提供服务的路由地点          uri: lb://cloud-payment-service          predicates:            - Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由
复制代码
测试

6.5.6 BeforeRoutePredicate

和AfterRoutePredicate类似,只是作用在指定时间之前,略。
6.5.7 BetweenRoutePredicateFactory

和之前类似,略
6.5.8 CookieRoutePredicate

官网例子

cookie的值,支持使用正则表达式。
  1. server:
  2.   port: 9527
  3. spring:
  4.   application:
  5.     name: cloud-gateway #以微服务注册进consul或nacos服务列表内
  6.   cloud:
  7.     consul: #配置consul地址
  8.       host: localhost
  9.       port: 8500
  10.       discovery:
  11.         prefer-ip-address: true
  12.         service-name: ${spring.application.name}    gateway:      routes:        - id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,发起配合服务名          #uri: http://localhost:8001                #匹配后提供服务的路由地点          uri: lb://cloud-payment-service          predicates:            - Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由            #- After=2024-10-29T21:06:17.219789300+08:00[Asia/Shanghai] #时中断言,再之后            #- Before=2024-10-30T21:06:17.219789300+08:00[Asia/Shanghai] #时中断言,之前            #- Between=2024-10-29T21:06:17.219789300+08:00[Asia/Shanghai],2024-10-30T21:06:17.219789300+08:00[Asia/Shanghai]            - Cookie=username,br.+x         #Cookie断言,,前是cookie键名 ,后是值,可以使用正则表达式        - id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,发起配合服务名          #uri: http://localhost:8001                #匹配后提供服务的路由地点          uri: lb://cloud-payment-service          predicates:            - Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由
复制代码
测试

6.5.9 HeaderRoutePredicate

官网示例
  1. server:
  2.   port: 9527
  3. spring:
  4.   application:
  5.     name: cloud-gateway #以微服务注册进consul或nacos服务列表内
  6.   cloud:
  7.     consul: #配置consul地址
  8.       host: localhost
  9.       port: 8500
  10.       discovery:
  11.         prefer-ip-address: true
  12.         service-name: ${spring.application.name}    gateway:      routes:        - id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,发起配合服务名          #uri: http://localhost:8001                #匹配后提供服务的路由地点          uri: lb://cloud-payment-service          predicates:            - Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由            #- After=2024-10-29T21:06:17.219789300+08:00[Asia/Shanghai] #时中断言,再之后            #- Before=2024-10-30T21:06:17.219789300+08:00[Asia/Shanghai] #时中断言,之前            #- Between=2024-10-29T21:06:17.219789300+08:00[Asia/Shanghai],2024-10-30T21:06:17.219789300+08:00[Asia/Shanghai]            #- Cookie=username,br.+x #Cookie断言,,前是cookie键名 ,后是值,可以使用正则表达式            - Header=X-Request-Id, \d+  # 请求头要有X-Request-Id属性,而且值为整数的正则表达式        - id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,发起配合服务名          #uri: http://localhost:8001                #匹配后提供服务的路由地点          uri: lb://cloud-payment-service          predicates:            - Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由
复制代码
测试

6.5.10 HostRoutePredicate

官网示例
  1. server:
  2.   port: 9527
  3. spring:
  4.   application:
  5.     name: cloud-gateway #以微服务注册进consul或nacos服务列表内
  6.   cloud:
  7.     consul: #配置consul地址
  8.       host: localhost
  9.       port: 8500
  10.       discovery:
  11.         prefer-ip-address: true
  12.         service-name: ${spring.application.name}    gateway:      routes:        - id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,发起配合服务名          #uri: http://localhost:8001                #匹配后提供服务的路由地点          uri: lb://cloud-payment-service          predicates:            - Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由            #- After=2024-10-29T21:06:17.219789300+08:00[Asia/Shanghai] #时中断言,再之后            #- Before=2024-10-30T21:06:17.219789300+08:00[Asia/Shanghai] #时中断言,之前            #- Between=2024-10-29T21:06:17.219789300+08:00[Asia/Shanghai],2024-10-30T21:06:17.219789300+08:00[Asia/Shanghai]            #- Cookie=username,br.+x #Cookie断言,,前是cookie键名 ,后是值,可以使用正则表达式            #- Header=X-Request-Id, \d+  # 请求头要有X-Request-Id属性,而且值为整数的正则表达式            - Host=**.atguigu.com        - id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,发起配合服务名          #uri: http://localhost:8001                #匹配后提供服务的路由地点          uri: lb://cloud-payment-service          predicates:            - Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由
复制代码
测试

6.5.11 PathRoutePredicate

一直就有该配置,略
  1. - Path=/pay/gateway/get/**
复制代码
6.5.12 QueryRoutePredicate

官网示例
  1. server:
  2.   port: 9527
  3. spring:
  4.   application:
  5.     name: cloud-gateway #以微服务注册进consul或nacos服务列表内
  6.   cloud:
  7.     consul: #配置consul地址
  8.       host: localhost
  9.       port: 8500
  10.       discovery:
  11.         prefer-ip-address: true
  12.         service-name: ${spring.application.name}    gateway:      routes:        - id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,发起配合服务名          #uri: http://localhost:8001                #匹配后提供服务的路由地点          uri: lb://cloud-payment-service          predicates:            - Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由            #- After=2024-10-29T21:06:17.219789300+08:00[Asia/Shanghai] #时中断言,再之后            #- Before=2024-10-30T21:06:17.219789300+08:00[Asia/Shanghai] #时中断言,之前            #- Between=2024-10-29T21:06:17.219789300+08:00[Asia/Shanghai],2024-10-30T21:06:17.219789300+08:00[Asia/Shanghai]            #- Cookie=username,br.+x #Cookie断言,,前是cookie键名 ,后是值,可以使用正则表达式            #- Header=X-Request-Id, \d+  # 请求头要有X-Request-Id属性,而且值为整数的正则表达式            #- Host=**.atguigu.com            - Query=username,\d+  # 要有参数名username而且值还要是整数才气路由        - id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,发起配合服务名          #uri: http://localhost:8001                #匹配后提供服务的路由地点          uri: lb://cloud-payment-service          predicates:            - Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由
复制代码
测试

6.5.13 RemoteAddrRoutePredicate

官网示例
  1. server:
  2.   port: 9527
  3. spring:
  4.   application:
  5.     name: cloud-gateway #以微服务注册进consul或nacos服务列表内
  6.   cloud:
  7.     consul: #配置consul地址
  8.       host: localhost
  9.       port: 8500
  10.       discovery:
  11.         prefer-ip-address: true
  12.         service-name: ${spring.application.name}    gateway:      routes:        - id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,发起配合服务名          #uri: http://localhost:8001                #匹配后提供服务的路由地点          uri: lb://cloud-payment-service          predicates:            - Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由            #- After=2024-10-29T21:06:17.219789300+08:00[Asia/Shanghai] #时中断言,再之后            #- Before=2024-10-30T21:06:17.219789300+08:00[Asia/Shanghai] #时中断言,之前            #- Between=2024-10-29T21:06:17.219789300+08:00[Asia/Shanghai],2024-10-30T21:06:17.219789300+08:00[Asia/Shanghai]            #- Cookie=username,br.+x #Cookie断言,,前是cookie键名 ,后是值,可以使用正则表达式            #- Header=X-Request-Id, \d+  # 请求头要有X-Request-Id属性,而且值为整数的正则表达式            #- Host=**.atguigu.com            #- Query=username,\d+  # 要有参数名username而且值还要是整数才气路由            - RemoteAddr=192.168.1.1/24 # 外部访问我的IP限定,最大跨度不超过32,现在是1~24它们是CIDR表现法。        - id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,发起配合服务名          #uri: http://localhost:8001                #匹配后提供服务的路由地点          uri: lb://cloud-payment-service          predicates:            - Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由
复制代码
CIDR表现法
CIDR(Classless Inter-Domain Routing),无类别域间路由是一个用于给用户分配IP地点以及在互联网上有效地路由IP数据包的对IP地点进行归类的方法。
大略说,给一个举例的ip/count,客户端请求的ip地点,从左到右,count个要和举例的ip雷同,才成功。
测试

6.5.14 MethodRoutePredicate

官网示例
  1. server:
  2.   port: 9527
  3. spring:
  4.   application:
  5.     name: cloud-gateway #以微服务注册进consul或nacos服务列表内
  6.   cloud:
  7.     consul: #配置consul地址
  8.       host: localhost
  9.       port: 8500
  10.       discovery:
  11.         prefer-ip-address: true
  12.         service-name: ${spring.application.name}    gateway:      routes:        - id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,发起配合服务名          #uri: http://localhost:8001                #匹配后提供服务的路由地点          uri: lb://cloud-payment-service          predicates:            - Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由            #- After=2024-10-29T21:06:17.219789300+08:00[Asia/Shanghai] #时中断言,再之后            #- Before=2024-10-30T21:06:17.219789300+08:00[Asia/Shanghai] #时中断言,之前            #- Between=2024-10-29T21:06:17.219789300+08:00[Asia/Shanghai],2024-10-30T21:06:17.219789300+08:00[Asia/Shanghai]            #- Cookie=username,br.+x #Cookie断言,,前是cookie键名 ,后是值,可以使用正则表达式            #- Header=X-Request-Id, \d+  # 请求头要有X-Request-Id属性,而且值为整数的正则表达式            #- Host=**.atguigu.com            #- Query=username,\d+  # 要有参数名username而且值还要是整数才气路由            #- RemoteAddr=192.168.1.7/24 # 外部访问我的IP限定,最大跨度不超过32,现在是1~24它们是 CIDR 表现法。            - Method=GET,POST        - id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,发起配合服务名          #uri: http://localhost:8001                #匹配后提供服务的路由地点          uri: lb://cloud-payment-service          predicates:            - Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由
复制代码
测试

6.5.15 总结

上述内置的Predicate,就是对请求,进行限定,满足限定通过,不满足,返回404。
6.6 自定义断言

类名,和自定义的保持一致XxxRoutePredicateFactory
6.6.1 扩展

扩展某些接口,或实现某些抽象类时,最简单,也最有效的方式,就是借鉴别人写好的示例。
这里,直接根据AfterRoutePredicateFactory类,作为模板,进行自定义。
6.6.2 完整代码
  1. package com.atguigu.cloud.mygateway;
  2. import jakarta.validation.constraints.NotNull;
  3. import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
  4. import org.springframework.cloud.gateway.handler.predicate.GatewayPredicate;
  5. import org.springframework.stereotype.Component;
  6. import org.springframework.web.server.ServerWebExchange;
  7. import java.util.Collections;
  8. import java.util.List;
  9. import java.util.function.Predicate;
  10. @Component
  11. public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config> {
  12.     public static final String USER_TYPE = "userType";
  13.     public MyRoutePredicateFactory() {
  14.         super(Config.class);
  15.     }
  16.     /** 支持Shortcut Configuration配置的方法 */
  17.     @Override
  18.     public List<String> shortcutFieldOrder() {
  19.         return Collections.singletonList(USER_TYPE);
  20.     }
  21.     public static class Config {
  22.         @NotNull
  23.         private String userType;
  24.         public String getUserType() {
  25.             return userType;
  26.         }
  27.         public void setUserType(String userType) {
  28.             this.userType = userType;
  29.         }
  30.     }
  31.     @Override
  32.     public Predicate<ServerWebExchange> apply(Config config) {
  33.         return new GatewayPredicate() {
  34.             @Override
  35.             public boolean test(ServerWebExchange serverWebExchange) {
  36.                 String userType = serverWebExchange.getRequest().getQueryParams().getFirst("userType");
  37.                 if (userType == null) return false;
  38.                 return userType.equals(config.getUserType());
  39.             }
  40.             @Override
  41.             public Object getConfig() {
  42.                 return config;
  43.             }
  44.             @Override
  45.             public String toString() {
  46.                 return String.format("UserType: %s", config.getUserType());
  47.             }
  48.         };
  49.     }
  50. }
复制代码
6.6.3 YML

这也是,为什么要类名要求是XxxRoutePredicateFactory
  1. - My=gold
复制代码
6.6.4 测试


6.7 Filter(过滤)

6.7.1 官网

https://docs.spring.io/spring-cloud-gateway/reference/spring-cloud-gateway/gatewayfilter-factories.html
6.7.2 介绍

类似于SpringMVC框架中的Interceptor,和Servlet体系中的Filter。
"pre"和"post"分别会在请求被执行前和被执行后调用,用来修改请求和相应信息。

6.7.3 作用

请求鉴权、异常处置处罚、统计接口调用时长等。
6.7.4 类型

有三类
全局默认过滤器Global Filters
全局官网地点
gateway出厂默认已有的,直接用即可,作用在所有的路由。不需要在配置文件中配置,作用在所有的路由上,实现GlobalFilter接口即可。
单一内置过滤器 Gateway Filter
单一官网介绍地点
此类型过滤器,也被称为网关过滤器,这种过滤器重要是作用于单一起由或者某个路由分组。
自定义过滤器
后续有案例。
6.8 Gateway内置的过滤器

官网
也即是上述分类中的单一内置过滤器GatewayFilter。

路由过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP相应。路由过滤器的作用域为特定路由。Spring Cloud Gateway包括许多内置的网关过滤器工厂。
从官网,可以看到,有30多个单一过滤器。课程中,只选择了一部分进行讲解。其他未讲到的内置过滤器,可以见Spring官网,都有配置案例,和解释
6.9 常用的内置过滤器

按照在HTTP请求中,所属的模块(请求头,请求参数,相应头,路径,其他),不同分为以下几组
6.9.1 请求头(RequestHeader)相关组

1.AddRequestHeader GatewayFilter Factory
添加请求头内容ByName
8001微服务,PayGateWayController新增接口
代码简单,就是获取请求头,打印,判断是否有特殊的请求头。
  1. @GetMapping(value = "/pay/gateway/filter")
  2. public ResultData<String> getGatewayFilter(HttpServletRequest request)
  3. {
  4.     String result = "";
  5.     Enumeration<String> headers = request.getHeaderNames();
  6.     while(headers.hasMoreElements())
  7.     {
  8.         String headName = headers.nextElement();
  9.         String headValue = request.getHeader(headName);
  10.         System.out.println("请求头名: " + headName +"\t\t\t"+"请求头值: " + headValue);
  11.         if(headName.equalsIgnoreCase("X-Request-atguigu1")
  12.                 || headName.equalsIgnoreCase("X-Request-atguigu2")) {
  13.             result = result+headName + "\t " + headValue +" ";
  14.         }
  15.     }
  16.     return ResultData.success("getGatewayFilter 过滤器 test: "+result+" \t "+ DateUtil.now());
  17. }
复制代码
9527网关YML添加过滤内容
注意以下为新增配置
  1. spring:
  2.   cloud:
  3.     gateway:
  4.       routes:
  5.         - id: pay_routh3 #pay_routh3                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
  6.           #uri: http://localhost:8001                #匹配后提供服务的路由地址
  7.           uri: lb://cloud-payment-service
  8.           predicates:
  9.             - Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由
  10.           filters:
  11.             - AddRequestHeader=X-Request-atguigu1,atguiguValue1 # 请求头kv,若添加多个请求头,则多写一行设置
  12.             - AddRequestHeader=X-Request-atguigu2,atguiguValue2
复制代码
重启9527和8001服务,请求 http://localhost:9527/pay/gateway/filter,会发现8001服务,打印的请求头中,有以下内容,只列举一部分。
  1. 请求头名: sec-fetch-site                        请求头值: none
  2. 请求头名: sec-fetch-mode                        请求头值: navigate
  3. 请求头名: x-request-atguigu1                        请求头值: atguiguValue1
  4. 请求头名: x-request-atguigu2                        请求头值: atguiguValue2
复制代码
2.RemoveRequestHeader GatewayFilter Factory
删除请求头ByName
修改Gateway配置前,从上述结果看,是有该请求头的。
修改YML
  1.         - id: pay_routh3 #pay_routh3                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
  2.           #uri: http://localhost:8001                #匹配后提供服务的路由地址
  3.           uri: lb://cloud-payment-service
  4.           predicates:
  5.             - Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由
  6.           filters:
  7.             - AddRequestHeader=X-Request-atguigu1,atguiguValue1 # 请求头kv,若添加多个请求头,则多写一行设置
  8.             - AddRequestHeader=X-Request-atguigu2,atguiguValue2
  9.             - RemoveRequestHeader=sec-fetch-site # 新增 删除请求头sec-fetch-site
复制代码
重启9527和8001,测试,请求 http://localhost:9527/pay/gateway/filter。
结果中,已经不包括sec-fetch-site请求头。
3.SetRequestHeader GatewayFilter Factory
修改请求头ByName
修改GatewayYML前,从AddRequestHeader结果看
  1. 请求头名: sec-fetch-mode                        请求头值: navigate
复制代码
修改YML
  1. - SetRequestHeader=sec-fetch-mode,Blue #修改请求头sec-fetch-mode
复制代码
重启9527和8001,测试,请求http://localhost:9527/pay/gateway/filter。
结果
  1. 请求头名: sec-fetch-mode                        请求头值: Blue
复制代码
6.9.2 请求参数(RequestParameter)相关组

1.AddRequestParameter GatewayFilter Factory
2.RemoveRequestParameter GatewayFilter Factory
上述两个,一起配置,测试
YML修改
  1.             - AddRequestParameter=breeze,001 #新增请求参数k,v
  2.             - RemoveRequestParameter=name #删除url请求参数name
复制代码
PayGatewayController#getGatewayFilter方法修改
  1.         System.out.println("=============================================");
  2.         String breeze = request.getParameter("breeze");
  3.         System.out.println("request Parameter breeze: "+breeze);
  4.         String name = request.getParameter("name");
  5.         System.out.println("request Parameter name: "+name);
  6.         System.out.println("=============================================");
复制代码
重启测试
1.访问 http://localhost:9527/pay/gateway/filter
  1. =============================================
  2. request Parameter breeze: 001
  3. request Parameter name: null
  4. =============================================
复制代码
2.访问http://localhost:9527/pay/gateway/filter?breeze=002&name=breeze
注意,AddRequestParameter只是一个兜底的,如果请求的参数中有其添加雷同的参数,则此配置无效,使用请求中的自带的。
还有,由于HTTP协议本身对于URL编码的要求,任何非ASCII字符(包括中文字符)都需要经过适当的编码才气正确传输,也就是说,如果想配置请求参数的value,为中文字符,则需要使用URL编码后的值,例如,风对应UTF-8 URL编码的结果为%E9%A3%8E。
  1. =============================================
  2. request Parameter breeze: 002
  3. request Parameter name: null
  4. =============================================
复制代码
6.9.3 相应头(ResponseHeader)相关组

开启配置前,看一下,http://localhost:9527/pay/gateway/filter 相应的相应头信息。

1.AddResponseHeader GatewayFilter Factory
2.SetResponseHeader GatewayFilter Factory
3.RemoveResponseHeader GatewayFilter Factory
新增YML配置
  1.             - AddResponseHeader=X-Response-atguigu,BlueResponse # 新增请求参数X-Response-atguigu并设值为BlueResponse
  2.             - SetResponseHeader=Date,2099-11-11 # 设置回应头Date值为2099-11-11
  3.             - RemoveResponseHeader=Content-Type # 将默认自带Content-Type回应属性删除
复制代码
重启,出现中文字符编程乱码的原因,移除了Content-Type 相应头,该相应头用于指示资源的媒体类型,即服务器发送的数据格式。这个头部字段非常重要,因为它告诉客户端(如浏览器)应该如何剖析接收到的数据。

6.9.4 前缀和路径相关组

1.PrefixPath GatewayFilter Factory
功能,主动添加路径前缀
之前正确的地点 http://localhost:9527/pay/gateway/filter
YML修改
  1.         - id: pay_routh3 #pay_routh3                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
  2.           #uri: http://localhost:8001                #匹配后提供服务的路由地址
  3.           uri: lb://cloud-payment-service
  4.           predicates:
  5.             #- Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由
  6.             - Path=/gateway/filter/**              # 断言,为配合PrefixPath测试过滤,暂时注释掉/pay
  7.           filters:
  8.             - AddRequestHeader=X-Request-atguigu1,atguiguValue1 # 请求头kv,若添加多个请求头,则多写一行设置
  9. #            - AddRequestHeader=X-Request-atguigu2,atguiguValue2
  10. #            - RemoveRequestHeader=sec-fetch-site # 删除请求头sec-fetch-site
  11. #            - SetRequestHeader=sec-fetch-mode,Blue #修改请求头sec-fetch-mode
  12. #            - AddRequestParameter=breeze,001   #新增请求参数k,v
  13. #            - RemoveRequestParameter=name #删除url请求参数name
  14. #            - AddResponseHeader=X-Response-atguigu,BlueResponse # 新增请求参数X-Response-atguigu并设值为BlueResponse
  15. #            - SetResponseHeader=Date,2099-11-11 # 设置回应头Date值为2099-11-11
  16. #            - RemoveResponseHeader=Content-Type # 将默认自带Content-Type回应属性删除
  17.             - PrefixPath=/pay # http://localhost:9527/pay/gateway/filter
复制代码
分拆,说明
之前完整正确地点:http://localhost:9527/pay/gateway/filter现在完整组合地点:PrefixPath + Path现实调用地点:http://localhost:9527/gateway/filter相当于说前缀被过滤器同一管理了。

还有StripPrefix GatewayFilter Factory,用以移除,前缀。

2.SetPath GatewayFilter Factory
访问路径修改
配置
  1.         - id: pay_routh3 #pay_routh3                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
  2.           #uri: http://localhost:8001                #匹配后提供服务的路由地址
  3.           uri: lb://cloud-payment-service
  4.           predicates:
  5.             #- Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由
  6.             #- Path=/gateway/filter/**              # 断言,为配合PrefixPath测试过滤,暂时注释掉/pay
  7.             - Path=/XYZ/abc/{segment}           # 断言,为配合SetPath测试,{segment}的内容最后被SetPath取代
  8.           filters:
  9.             - AddRequestHeader=X-Request-atguigu1,atguiguValue1 # 请求头kv,若添加多个请求头,则多写一行设置
  10. #            - AddRequestHeader=X-Request-atguigu2,atguiguValue2
  11. #            - RemoveRequestHeader=sec-fetch-site # 删除请求头sec-fetch-site
  12. #            - SetRequestHeader=sec-fetch-mode,Blue #修改请求头sec-fetch-mode
  13. #            - AddRequestParameter=breeze,001   #新增请求参数k,v
  14. #            - RemoveRequestParameter=name #删除url请求参数name
  15. #            - AddResponseHeader=X-Response-atguigu,BlueResponse # 新增请求参数X-Response-atguigu并设值为BlueResponse
  16. #            - SetResponseHeader=Date,2099-11-11 # 设置回应头Date值为2099-11-11
  17. #            - RemoveResponseHeader=Content-Type # 将默认自带Content-Type回应属性删除
  18. #            - PrefixPath=/pay # http://localhost:9527/pay/gateway/filter
  19.             - SetPath=/pay/gateway/{segment}  # {segment}表示占位符,你写abc也行但要上下一致
复制代码
配置说明
/XYZ/abc/{segment}就是个占位符,等价于SetPath背面指定的{segment}内容浏览器访问地点: http://localhost:9527/XYZ/abc/filter
现实微服务地点:http://localhost:9527/pay/gateway/filter
结果,浏览器,显示请求 url:http://localhost:9527/XYZ/abc/filter 但是,最终请求的地点 http://localhost:9527/pay/gateway/filter
3.RedirectTo GatewayFilter Factory
重定向到某个页面
  1.         - id: pay_routh3 #pay_routh3                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
  2.           uri: lb://cloud-payment-service
  3.           predicates:
  4.             - Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由
  5.             #- Path=/gateway/filter/**              # 断言,为配合PrefixPath测试过滤,暂时注释掉/pay
  6.             #- Path=/XYZ/abc/{segment}           # 断言,为配合SetPath测试,{segment}的内容最后被SetPath取代
  7.           filters:
  8.             - AddRequestHeader=X-Request-atguigu1,atguiguValue1 # 请求头kv,若添加多个请求头,则多写一行设置
  9. #            - AddRequestHeader=X-Request-atguigu2,atguiguValue2
  10. #            - RemoveRequestHeader=sec-fetch-site # 删除请求头sec-fetch-site
  11. #            - SetRequestHeader=sec-fetch-mode,Blue #修改请求头sec-fetch-mode
  12. #            - AddRequestParameter=breeze,001   #新增请求参数k,v
  13. #            - RemoveRequestParameter=name #删除url请求参数name
  14. #            - AddResponseHeader=X-Response-atguigu,BlueResponse # 新增请求参数X-Response-atguigu并设值为BlueResponse
  15. #            - SetResponseHeader=Date,2099-11-11 # 设置回应头Date值为2099-11-11
  16. #            - RemoveResponseHeader=Content-Type # 将默认自带Content-Type回应属性删除
  17. #            - PrefixPath=/pay # http://localhost:9527/pay/gateway/filter
  18. #            - SetPath=/pay/gateway/{segment}  # {segment}表示占位符,你写abc也行但要上下一致
  19.             - RedirectTo=302, https://www.bilibili.com/video/BV1gW421P7RD # 访问http://localhost:9527/pay/gateway/filter重定向到https://www.bilibili.com/video/BV1gW421P7RD
复制代码
重启9527,测试,略。
6.9.5 其他

Default Filters

这样配置的,单一条件过滤器,就变成了全局过滤器,实用于所有断言匹配的router。
本次案例,全部YML配置
  1. server:
  2.   port: 9527
  3. spring:
  4.   application:
  5.     name: cloud-gateway #以微服务注册进consul或nacos服务列表内
  6.   cloud:
  7.     consul: #配置consul地址
  8.       host: localhost
  9.       port: 8500
  10.       discovery:
  11.         prefer-ip-address: true
  12.         service-name: ${spring.application.name}    gateway:      routes:        - id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,发起配合服务名          #uri: http://localhost:8001                #匹配后提供服务的路由地点          uri: lb://cloud-payment-service          predicates:            - Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由            #- After=2024-10-29T21:06:17.219789300+08:00[Asia/Shanghai] #时中断言,再之后            #- Before=2024-10-30T21:06:17.219789300+08:00[Asia/Shanghai] #时中断言,之前            #- Between=2024-10-29T21:06:17.219789300+08:00[Asia/Shanghai],2024-10-30T21:06:17.219789300+08:00[Asia/Shanghai]            #- Cookie=username,br.+x #Cookie断言,,前是cookie键名 ,后是值,可以使用正则表达式            #- Header=X-Request-Id, \d+  # 请求头要有X-Request-Id属性,而且值为整数的正则表达式            #- Host=**.atguigu.com            #- Query=username,\d+  # 要有参数名username而且值还要是整数才气路由            #- RemoteAddr=192.168.1.7/24 # 外部访问我的IP限定,最大跨度不超过32,现在是1~24它们是 CIDR 表现法。            #- Method=GET,POST            - My=gold        - id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,发起配合服务名          #uri: http://localhost:8001                #匹配后提供服务的路由地点          uri: lb://cloud-payment-service          predicates:            - Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由        - id: pay_routh3 #pay_routh3                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,发起配合服务名          #uri: http://localhost:8001                #匹配后提供服务的路由地点          uri: lb://cloud-payment-service          predicates:            - Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由            #- Path=/gateway/filter/**              # 断言,为配合PrefixPath测试过滤,暂时解释掉/pay            #- Path=/XYZ/abc/{segment}           # 断言,为配合SetPath测试,{segment}的内容最后被SetPath取代          filters:            - AddRequestHeader=X-Request-atguigu1,atguiguValue1 # 请求头kv,若添加多个请求头,则多写一行设置#            - AddRequestHeader=X-Request-atguigu2,atguiguValue2#            - RemoveRequestHeader=sec-fetch-site # 删除请求头sec-fetch-site#            - SetRequestHeader=sec-fetch-mode,Blue #修改请求头sec-fetch-mode#            - AddRequestParameter=breeze,001   #新增请求参数k,v#            - RemoveRequestParameter=name #删除url请求参数name#            - AddResponseHeader=X-Response-atguigu,BlueResponse # 新增请求参数X-Response-atguigu并设值为BlueResponse#            - SetResponseHeader=Date,2099-11-11 # 设置回应头Date值为2099-11-11#            - RemoveResponseHeader=Content-Type # 将默认自带Content-Type回应属性删除#            - PrefixPath=/pay # http://localhost:9527/pay/gateway/filter#            - SetPath=/pay/gateway/{segment}  # {segment}表现占位符,你写abc也行但要上下一致            - RedirectTo=302, https://www.bilibili.com/video/BV1gW421P7RD # 访问http://localhost:9527/pay/gateway/filter重定向到https://www.bilibili.com/video/BV1gW421P7RD
复制代码
6.10 Gateway自定义过滤器

6.10.1 自定义全局Filter

面试题,统计接口调用耗时情况
通过自定义全局过滤器搞定上述情况。
自定义全局过滤器,官网
https://docs.spring.io/spring-cloud-gateway/reference/spring-cloud-gateway/global-filters.html
该页面有案例
编码
  1. import org.slf4j.Logger;
  2. import org.slf4j.LoggerFactory;
  3. import org.springframework.cloud.gateway.filter.GatewayFilterChain;
  4. import org.springframework.cloud.gateway.filter.GlobalFilter;
  5. import org.springframework.core.Ordered;
  6. import org.springframework.stereotype.Component;
  7. import org.springframework.web.server.ServerWebExchange;
  8. import reactor.core.publisher.Mono;
  9. /**
  10. * 记录访问日志的Gateway全局过滤器
  11. */
  12. @Component
  13. public class RecordVisitLogGlobalFilter implements GlobalFilter, Ordered {
  14.     public static final Logger logger = LoggerFactory.getLogger(RecordVisitLogGlobalFilter.class);
  15.     public static final String BEGIN_VISIT_TIME = "beginVisitTime";//开始访问时间
  16.     @Override
  17.     public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
  18.         //记录访问接口的开始时间
  19.         exchange.getAttributes().put(BEGIN_VISIT_TIME,System.currentTimeMillis());
  20.         return chain.filter(exchange).then(Mono.fromRunnable(() -> {
  21.             Long beginVisitTime = exchange.getAttribute(BEGIN_VISIT_TIME);
  22.             if (beginVisitTime != null) {
  23.                 logger.info("访问接口主机: " + exchange.getRequest().getURI().getHost());
  24.                 logger.info("访问接口端口: " + exchange.getRequest().getURI().getPort());
  25.                 logger.info("访问接口URL: " + exchange.getRequest().getURI().getPath());
  26.                 logger.info("访问接口URL参数: " + exchange.getRequest().getURI().getRawQuery());
  27.                 logger.info("访问接口时长: " + (System.currentTimeMillis() - beginVisitTime) + "ms");
  28.                 logger.info("###################################################");
  29.                 System.out.println();
  30.             }
  31.         }));
  32.     }
  33.     @Override
  34.     public int getOrder() {
  35.         return -1;//设置优先级,值越小优先级越高
  36.     }
  37. }
复制代码
YML修改
  1. server:
  2.   port: 9527
  3. spring:
  4.   application:
  5.     name: cloud-gateway #以微服务注册进consul或nacos服务列表内
  6.   cloud:
  7.     consul: #配置consul地址
  8.       host: localhost
  9.       port: 8500
  10.       discovery:
  11.         prefer-ip-address: true
  12.         service-name: ${spring.application.name}    gateway:      routes:        - id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,发起配合服务名          #uri: http://localhost:8001                #匹配后提供服务的路由地点          uri: lb://cloud-payment-service          predicates:            - Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由            #- After=2024-10-29T21:06:17.219789300+08:00[Asia/Shanghai] #时中断言,再之后            #- Before=2024-10-30T21:06:17.219789300+08:00[Asia/Shanghai] #时中断言,之前            #- Between=2024-10-29T21:06:17.219789300+08:00[Asia/Shanghai],2024-10-30T21:06:17.219789300+08:00[Asia/Shanghai]            #- Cookie=username,br.+x #Cookie断言,,前是cookie键名 ,后是值,可以使用正则表达式            #- Header=X-Request-Id, \d+  # 请求头要有X-Request-Id属性,而且值为整数的正则表达式            #- Host=**.atguigu.com            #- Query=username,\d+  # 要有参数名username而且值还要是整数才气路由            #- RemoteAddr=192.168.1.7/24 # 外部访问我的IP限定,最大跨度不超过32,现在是1~24它们是 CIDR 表现法。            #- Method=GET,POST            #- My=gold        - id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,发起配合服务名          #uri: http://localhost:8001                #匹配后提供服务的路由地点          uri: lb://cloud-payment-service          predicates:            - Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由        - id: pay_routh3 #pay_routh3                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,发起配合服务名          #uri: http://localhost:8001                #匹配后提供服务的路由地点          uri: lb://cloud-payment-service          predicates:            - Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由            #- Path=/gateway/filter/**              # 断言,为配合PrefixPath测试过滤,暂时解释掉/pay            #- Path=/XYZ/abc/{segment}           # 断言,为配合SetPath测试,{segment}的内容最后被SetPath取代          filters:            - AddRequestHeader=X-Request-atguigu1,atguiguValue1 # 请求头kv,若添加多个请求头,则多写一行设置#            - AddRequestHeader=X-Request-atguigu2,atguiguValue2#            - RemoveRequestHeader=sec-fetch-site # 删除请求头sec-fetch-site#            - SetRequestHeader=sec-fetch-mode,Blue #修改请求头sec-fetch-mode#            - AddRequestParameter=breeze,001   #新增请求参数k,v#            - RemoveRequestParameter=name #删除url请求参数name#            - AddResponseHeader=X-Response-atguigu,BlueResponse # 新增请求参数X-Response-atguigu并设值为BlueResponse#            - SetResponseHeader=Date,2099-11-11 # 设置回应头Date值为2099-11-11#            - RemoveResponseHeader=Content-Type # 将默认自带Content-Type回应属性删除#            - PrefixPath=/pay # http://localhost:9527/pay/gateway/filter#            - SetPath=/pay/gateway/{segment}  # {segment}表现占位符,你写abc也行但要上下一致#            - RedirectTo=302, https://www.bilibili.com/video/BV1gW421P7RD # 访问http://localhost:9527/pay/gateway/filter重定向到https://www.bilibili.com/video/BV1gW421P7RD
复制代码
测试结果

6.10.2 自定义条件过滤器

自定义单一过滤器GatewayFilter
参考Gateway内置的过滤器,比如AddResponseHeaderGatewayFilterFactory,SetResponseHeaderGatewayFilterFactory等。
自定义网关过滤器规则,和自定义断言类似
新建类名要以XxxGatewayFilterFactory,并继承AbstractGatewayFilterFactory类,新建XxxGatewayFilterFactory.Config内部类,重写apply方法,重写shortcutFieldOrder方法等,详细见编码。
编码
  1. import org.springframework.cloud.gateway.filter.GatewayFilter;
  2. import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
  3. import org.springframework.http.HttpStatus;
  4. import org.springframework.http.server.reactive.ServerHttpRequest;
  5. import java.util.Arrays;
  6. import java.util.List;
  7. @Component
  8. public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.Config> {
  9.     public MyGatewayFilterFactory() {
  10.         super(MyGatewayFilterFactory.Config.class);
  11.     }
  12.     @Override
  13.     public GatewayFilter apply(Config config) {
  14.         return (exchange, chain) -> {
  15.             ServerHttpRequest request = exchange.getRequest();
  16.             String configStatus = config.getStatus();//配置的值
  17.             System.out.println("进入了自定义网关过滤器MyGatewayFilterFactory,status:" + configStatus);
  18.             if (request.getQueryParams().containsKey(configStatus)) {
  19.                 return chain.filter(exchange);
  20.             } else {
  21.                 exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);
  22.                 return exchange.getResponse().setComplete();
  23.             }
  24.         };
  25.     }
  26.     public static class Config {
  27.         private String status;//设置一个状态值,等于多少,才可以访问
  28.         public String getStatus() {
  29.             return status;
  30.         }
  31.         public void setStatus(String status) {
  32.             this.status = status;
  33.         }
  34.     }
  35.     /**
  36.      * 支持Shortcut Configuration配置的方法
  37.      */
  38.     @Override
  39.     public List<String> shortcutFieldOrder() {
  40.         return Arrays.asList("status");
  41.     }
  42. }
复制代码
YML配置
  1. server:
  2.   port: 9527
  3. spring:
  4.   application:
  5.     name: cloud-gateway #以微服务注册进consul或nacos服务列表内
  6.   cloud:
  7.     consul: #配置consul地址
  8.       host: localhost
  9.       port: 8500
  10.       discovery:
  11.         prefer-ip-address: true
  12.         service-name: ${spring.application.name}    gateway:      routes:        - id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,发起配合服务名          #uri: http://localhost:8001                #匹配后提供服务的路由地点          uri: lb://cloud-payment-service          predicates:            - Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由            #- After=2024-10-29T21:06:17.219789300+08:00[Asia/Shanghai] #时中断言,再之后            #- Before=2024-10-30T21:06:17.219789300+08:00[Asia/Shanghai] #时中断言,之前            #- Between=2024-10-29T21:06:17.219789300+08:00[Asia/Shanghai],2024-10-30T21:06:17.219789300+08:00[Asia/Shanghai]            #- Cookie=username,br.+x #Cookie断言,,前是cookie键名 ,后是值,可以使用正则表达式            #- Header=X-Request-Id, \d+  # 请求头要有X-Request-Id属性,而且值为整数的正则表达式            #- Host=**.atguigu.com            #- Query=username,\d+  # 要有参数名username而且值还要是整数才气路由            #- RemoteAddr=192.168.1.7/24 # 外部访问我的IP限定,最大跨度不超过32,现在是1~24它们是 CIDR 表现法。            #- Method=GET,POST            #- My=gold        - id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,发起配合服务名          #uri: http://localhost:8001                #匹配后提供服务的路由地点          uri: lb://cloud-payment-service          predicates:            - Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由        - id: pay_routh3 #pay_routh3                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,发起配合服务名          #uri: http://localhost:8001                #匹配后提供服务的路由地点          uri: lb://cloud-payment-service          predicates:            - Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由            #- Path=/gateway/filter/**              # 断言,为配合PrefixPath测试过滤,暂时解释掉/pay            #- Path=/XYZ/abc/{segment}           # 断言,为配合SetPath测试,{segment}的内容最后被SetPath取代          filters:            - My=atguigu #这也是为什么自定义的条件过滤器的类型要满足XxxGatewayFilterFactory的原因            - AddRequestHeader=X-Request-atguigu1,atguiguValue1 # 请求头kv,若添加多个请求头,则多写一行设置#            - AddRequestHeader=X-Request-atguigu2,atguiguValue2#            - RemoveRequestHeader=sec-fetch-site # 删除请求头sec-fetch-site#            - SetRequestHeader=sec-fetch-mode,Blue #修改请求头sec-fetch-mode#            - AddRequestParameter=breeze,001   #新增请求参数k,v#            - RemoveRequestParameter=name #删除url请求参数name#            - AddResponseHeader=X-Response-atguigu,BlueResponse # 新增请求参数X-Response-atguigu并设值为BlueResponse#            - SetResponseHeader=Date,2099-11-11 # 设置回应头Date值为2099-11-11#            - RemoveResponseHeader=Content-Type # 将默认自带Content-Type回应属性删除#            - PrefixPath=/pay # http://localhost:9527/pay/gateway/filter#            - SetPath=/pay/gateway/{segment}  # {segment}表现占位符,你写abc也行但要上下一致#            - RedirectTo=302, https://www.bilibili.com/video/BV1gW421P7RD # 访问http://localhost:9527/pay/gateway/filter重定向到https://www.bilibili.com/video/BV1gW421P7RD
复制代码
测试结果
http://localhost:9527/pay/gateway/filter 报错状态码400
http://localhost:9527/pay/gateway/filter?atguigu=x 访问成功
7.Gateway整合Sentinel实现容错

见SpringCloud Alibaba章节。
只是为了记录自己的学习历程,且本人水平有限,不对之处,请指正。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

数据人与超自然意识

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表