当前位置: 首页 > news >正文

07-SpringCloud-Gateway新一代网关

一、概述

1、Gateway介绍

官网:https://spring.io/projects/spring-cloud-gateway

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

作用:

  • 反向代理
  • 鉴权
  • 流量监控
  • 熔断
  • 日志监控

在这里插入图片描述

在这里插入图片描述

2、Gateway三大核心

  • Route(路由):路由是构建网关的基本模块,它由ID,目标URL,一系列的断言和过滤器组成,如果断言为true则匹配该路由;
  • Predicate(断言):(java.util.function.Predicate)开发人员可以匹配HTTP请求中的所有内容(请求头和请求体),如果请求与断言相匹配则进行路由;
  • Filter(过滤):指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后进行修改。

在这里插入图片描述

web前端请求,通过一些匹配条件,定位到真正的服务节点。并在这个转发过程的前后,进行一些精细化控制。

predicate就是我们的匹配条件;

filter,就可以理解为一个无所不能的拦截器。有了这两个元素,再加上目标uri,就可以实现一个具体的路由了。

3、Gateway工作流程

核心逻辑:路由转发+断言判断+执行过滤链

在这里插入图片描述

客户端向 Spring Cloud Gateway 发出请求。然后在 Gateway Handler Mapping 中找到与请求相匹配的路由,将其发送到 Gateway Web Handler。Handler 再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。

过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前(Pre)或之后(Post)执行业务逻辑。

在“pre”类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等;

在“post”类型的过滤器中可以做响应内容、响应头的修改,日志的输出,流量监控等有着非常重要的作用。

二、入门配置

1、建Module

新建 cloud-gateway9527 模块

在这里插入图片描述

2、改POM

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>com.atguigu.cloud</groupId><artifactId>cloud2024</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>cloud-gateway9527</artifactId><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!--gateway--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><!--服务注册发现consul discovery,网关也要注册进服务注册中心统一管控--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-consul-discovery</artifactId></dependency><!-- 指标监控健康检查的actuator,网关是响应式编程删除掉spring-boot-starter-web dependency--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

3、写YML

server:port: 9527spring:application:name: cloud-gateway #以微服务注册进consul或nacos服务列表内cloud:consul: #配置consul地址host: localhostport: 8500discovery:prefer-ip-address: trueservice-name: ${spring.application.name}

4、主启动

package com.atguigu.cloud;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;@SpringBootApplication
@EnableDiscoveryClient //服务注册与发现
public class Main9527 {public static void main(String[] args) {SpringApplication.run(Main9527.class, args);}
}

5、测试

在这里插入图片描述

三、路由映射

不暴露8001端口,希望在8001真正的支付微服务外面套一层9527网关

1、改造8001模块

新建PayGateWayController

package com.atguigu.cloud.controller;import cn.hutool.core.util.IdUtil;
import com.atguigu.cloud.entities.Pay;
import com.atguigu.cloud.resp.ResultData;
import com.atguigu.cloud.service.PayService;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;/*** @ClassName PayGateWayController* @Author link* @Date: 2024/11/6 下午3:56* @Version v1.0* @Description:*/
@RestController
public class PayGateWayController {@ResourcePayService payService;@GetMapping(value = "/pay/gateway/get/{id}")public ResultData<Pay> getById(@PathVariable("id") Integer id){Pay pay = payService.getById(id);return ResultData.success(pay);}@GetMapping(value = "/pay/gateway/info")public ResultData<String> getGatewayInfo(){return ResultData.success("gateway info test:"+ IdUtil.simpleUUID());}
}

2、9527模块YML配置

server:port: 9527spring:application:name: cloud-gateway #以微服务注册进consul或nacos服务列表内cloud:consul: #配置consul地址host: localhostport: 8500discovery:prefer-ip-address: trueservice-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/**              # 断言,路径相匹配的进行路由

3、修改公共api模块

package com.atguigu.cloud.apis;import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import com.atguigu.cloud.entities.Pay;
import com.atguigu.cloud.entities.PayDTO;
import com.atguigu.cloud.resp.ResultData;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;import java.util.List;/*** @ClassName PayFeignApi* @description: 通用api* @author: linkai* @create: 2024-11-03 15:29**/
@FeignClient(value = "cloud-payment-service")
public interface PayFeignApi {@PostMapping(value = "/pay/add")@Operation(summary = "新增",description = "新增支付流水方法")public ResultData addPay(@org.springframework.web.bind.annotation.RequestBody PayDTO payDTO);@DeleteMapping(value = "/pay/del/{id}")@Operation(summary = "删除",description = "删除支付流水方法")public  ResultData deletePay(@PathVariable("id") Integer id);@PutMapping(value = "/pay/update")@Operation(summary = "修改",description = "修改支付流水方法")public ResultData updatePay(@RequestBody PayDTO payDTO);@GetMapping(value = "/pay/get/{id}")@Operation(summary = "查询",description = "根据id查询支付流水方法")public ResultData getPayById(@PathVariable("id") Integer id);@GetMapping(value = "/pay/getPayList")@Operation(summary = "查询全部",description = "查询全部支付流水方法")public ResultData getPayList();/*** openfeign天然支持负载均衡演示* @return*/@GetMapping(value = "/pay/get/info")public String getInfoByConsul();/**** Resilience4j CircuitBreaker 的例子**/@GetMapping(value = "/pay/circuit/{id}")public String myCircuit(@PathVariable("id") Integer id);/**** Resilience4j Bulkhead  的例子**/@GetMapping(value = "/pay/bulkhead/{id}")public String myBulkhead(@PathVariable("id") Integer id);/**** Resilience4j Ratelimit  的例子**/@GetMapping(value = "/pay/ratelimit/{id}")public String myRatelimit(@PathVariable("id") Integer id);/**** Micrometer 链路追踪 的例子**/@GetMapping(value = "/pay/micrometer/{id}")public String myMicrometer(@PathVariable("id") Integer id);/*** Gateway 网关**/@GetMapping(value = "/pay/gateway/get/{id}")public ResultData getById(@PathVariable("id") Integer id);@GetMapping(value = "/pay/gateway/info")public ResultData<String> getGatewayInfo();}

4、修改feign-order80模块

新建OrderGateWayController

package com.atguigu.cloud.controller;import com.atguigu.cloud.apis.PayFeignApi;
import com.atguigu.cloud.entities.Pay;
import com.atguigu.cloud.resp.ResultData;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;/*** @ClassName OrderGateWayController* @Author link* @Date: 2024/11/6 下午4:10* @Version v1.0* @Description:*/
@RestController
public class OrderGateWayController {@Resourceprivate PayFeignApi payFeignApi;@GetMapping(value = "/feign/pay/gateway/get/{id}")public ResultData getById(@PathVariable("id") Integer id){return payFeignApi.getById(id);}@GetMapping(value = "/feign/pay/gateway/info")public ResultData<String> getGatewayInfo(){return payFeignApi.getGatewayInfo();}
}

5、测试

测试一:8001和9527访问

在这里插入图片描述

测试二:启动订单80服务,用80访问

在这里插入图片描述

但是这时候我们停掉网关也是一样可以访问,这是因为我们在PayFeignApi中定义通过找8001这个服务,需要改成网关服务

在这里插入图片描述

现在我们停掉网关:

在这里插入图片描述

开启网关:

在这里插入图片描述

四、Gateway高级特性

1、Route以微服务名-动态获取微服务URL

把uri的ip地址改成服务名称,如uri: lb: //cloud-payment-service

修改后的yml

xmserver:port: 9527spring:application:name: cloud-gateway #以微服务注册进consul或nacos服务列表内cloud:consul: #配置consul地址host: localhostport: 8500discovery:prefer-ip-address: trueservice-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/**              # 断言,路径相匹配的进行路由

这样之后我们修改8001服务的端口,也不会受到影响

在这里插入图片描述

2、Predicate断言(谓语)

配置方式两种:

快捷方式配置

快捷方式配置由过滤器名称识别,后跟等号(=),后跟用逗号分隔的参数值(,)。

应用程序.yml

spring:cloud:gateway:routes:- id: after_routeuri: https://example.orgpredicates:- Cookie=mycookie,mycookievalue

前面的示例定义了CookieRoute Predicate Factory,它有两个参数:cookie 名称mycookie和要匹配的值mycookievalue

充分展开配置

完全展开的参数看起来更像带有名称/值对的标准 yaml 配置。通常,会有一个name键和一个args键。args键是用于配置谓词或过滤器的键值对的映射。

应用程序.yml

spring:cloud:gateway:routes:- id: after_routeuri: https://example.orgpredicates:- name: Cookieargs:name: mycookieregexp: mycookievalue
1)常用的内置Route Predicate(2024.11月份最新 4.1.5版本)

以http://localhost:9527/pay/gateway/get/1地址为例,测试断言

1:After Request Predicate(请求后断言)

路由After谓词工厂采用一个参数 a datetime(即 java ZonedDateTime)。此谓词匹配在指定日期时间之后发生的请求。以下示例配置了 after 路由谓词:

应用程序.yml

spring:cloud:gateway:mvc:routes:- id: after_routeuri: https://example.orgpredicates:- After=2017-01-20T17:42:47.789-07:00[America/Denver]

获得ZonedDateTime示例:

package com.atguigu.cloud.util;import java.time.ZonedDateTime;/*** @ClassName CreateZoneDateTime* @Author link* @Date: 2024/11/7 上午8:51* @Version v1.0* @Description:*/
public class CreateZoneDateTime {public static void main(String[] args) {ZonedDateTime now = ZonedDateTime.now();System.out.println(now);}
}

修改9527YML

server:port: 9527spring:application:name: cloud-gateway #以微服务注册进consul或nacos服务列表内cloud:consul: #配置consul地址host: localhostport: 8500discovery:prefer-ip-address: trueservice-name: ${spring.application.name}gateway:routes:- id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:- After=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai]#- 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/**              # 断言,路径相匹配的进行路由
2:Before Request Predicate(请求前断言)

路由Before谓词工厂接受一个参数 a datetime(即 java ZonedDateTime)。此谓词匹配在指定 之前发生的请求datetime。以下示例配置了一个 before 路由谓词:

应用程序.yml

spring:cloud:gateway:mvc:routes:- id: before_routeuri: https://example.orgpredicates:- Before=2017-01-20T17:42:47.789-07:00[America/Denver]

修改9527YML

server:port: 9527spring:application:name: cloud-gateway #以微服务注册进consul或nacos服务列表内cloud:consul: #配置consul地址host: localhostport: 8500discovery:prefer-ip-address: trueservice-name: ${spring.application.name}gateway:routes:- id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:- Before=2024-11-07T09:05:00.797682100+08:00[America/Denver]#- After=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai]#- 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/**              # 断言,路径相匹配的进行路由
3:Between Request Predicate(两者之间断言)

路由Between谓词工厂接受两个参数,datetime1和,datetime2 它们是 JavaZonedDateTime对象。此谓词匹配发生在 之后datetime1和 之前的请求datetime2datetime2参数必须是 之后datetime1。以下示例配置了一个 之间 路由谓词:

应用程序.yml

spring:cloud:gateway:mvc:routes:- id: between_routeuri: https://example.orgpredicates:- Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]

修改9527YML

server:port: 9527spring:application:name: cloud-gateway #以微服务注册进consul或nacos服务列表内cloud:consul: #配置consul地址host: localhostport: 8500discovery:prefer-ip-address: trueservice-name: ${spring.application.name}gateway:routes:- id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:- Between=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai], 2024-11-07T09:08:00.797682100+08:00[America/Denver]#- Before=2024-11-07T09:05:00.797682100+08:00[America/Denver]#- After=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai]#- 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/**              # 断言,路径相匹配的进行路由
4:Cookie Request Predicate(Cookie请求断言)

路由Cookie谓词工厂采用两个参数,cookiename和 a regexp(Java 正则表达式)。此谓词匹配具有给定名称且其值与正则表达式匹配的 cookie。以下示例配置 cookie 路由谓词工厂:

应用程序.yml

spring:cloud:gateway:mvc:routes:- id: cookie_routeuri: https://example.orgpredicates:- Cookie=chocolate, ch.p

修改9527YML

server:port: 9527spring:application:name: cloud-gateway #以微服务注册进consul或nacos服务列表内cloud:consul: #配置consul地址host: localhostport: 8500discovery:prefer-ip-address: trueservice-name: ${spring.application.name}gateway:routes:- id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:- Cookie=username,link# - Between=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai], 2024-11-07T09:08:00.797682100+08:00[America/Denver]#- Before=2024-11-07T09:05:00.797682100+08:00[America/Denver]#- After=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai]- 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/**              # 断言,路径相匹配的进行路由
5:Header Request Predicate(标头请求断言)

路由Header谓词工厂采用两个参数,即header和 a regexp(Java 正则表达式)。此谓词与具有给定名称且值与正则表达式匹配的标头匹配。以下示例配置标头路由谓词:

应用程序.yml

spring:cloud:gateway:mvc:routes:- id: header_routeuri: https://example.orgpredicates:- Header=X-Request-Id, \d+

修改9527YML

server:port: 9527spring:application:name: cloud-gateway #以微服务注册进consul或nacos服务列表内cloud:consul: #配置consul地址host: localhostport: 8500discovery:prefer-ip-address: trueservice-name: ${spring.application.name}gateway:routes:- id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:- Header=X-Request-Id, \d+# - Cookie=username,link# - Between=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai], 2024-11-07T09:08:00.797682100+08:00[America/Denver]#- Before=2024-11-07T09:05:00.797682100+08:00[America/Denver]#- After=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai]- 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:Host Request Predicate(主机请求断言)

路由Host谓词工厂采用一个参数:主机名列表patterns。该模式是 Ant 样式的模式,以.作为分隔符。此谓词匹配与Host模式匹配的标头。以下示例配置主机路由谓词:

应用程序.yml

spring:cloud:gateway:mvc:routes:- id: host_routeuri: https://example.orgpredicates:- Host=**.somehost.org,**.anotherhost.org

修改9527YML

server:port: 9527spring:application:name: cloud-gateway #以微服务注册进consul或nacos服务列表内cloud:consul: #配置consul地址host: localhostport: 8500discovery:prefer-ip-address: trueservice-name: ${spring.application.name}gateway:routes:- id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:- Host=**.atguigu.com#- Header=X-Request-Id, \d+# - Cookie=username,link# - Between=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai], 2024-11-07T09:08:00.797682100+08:00[America/Denver]#- Before=2024-11-07T09:05:00.797682100+08:00[America/Denver]#- After=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai]- 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/**              # 断言,路径相匹配的进行路由
7:Method Request Predicate(方法请求断言)

请求谓词Method接受methods一个或多个参数:要匹配的 HTTP 方法。以下示例配置方法路由谓词:

应用程序.yml

spring:cloud:gateway:mvc:routes:- id: method_routeuri: https://example.orgpredicates:- Method=GET,POST

修改9527YML

server:port: 9527spring:application:name: cloud-gateway #以微服务注册进consul或nacos服务列表内cloud:consul: #配置consul地址host: localhostport: 8500discovery:prefer-ip-address: trueservice-name: ${spring.application.name}gateway:routes:- id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:- Method=GET,POST#- Host=**.atguigu.com#- Header=X-Request-Id, \d+# - Cookie=username,link# - Between=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai], 2024-11-07T09:08:00.797682100+08:00[America/Denver]#- Before=2024-11-07T09:05:00.797682100+08:00[America/Denver]#- After=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai]- 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/**              # 断言,路径相匹配的进行路由
8:Path Request Predicate(路径请求断言)

Request PathPredicate 接受两个参数:一个 Spring 列表PathPattern patterns。此 Request Predicate 使用RequestPredicates.path()作为底层实现。以下示例配置路径路由谓词:

应用程序.yml

spring:cloud:gateway:mvc:routes:- id: path_routeuri: https://example.orgpredicates:- Path=/red/{segment},/blue/{segment}

修改9527YML

server:port: 9527spring:application:name: cloud-gateway #以微服务注册进consul或nacos服务列表内cloud:consul: #配置consul地址host: localhostport: 8500discovery:prefer-ip-address: trueservice-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/**              # 断言,路径相匹配的进行路由#- Method=GET,POST#- Host=**.atguigu.com#- Header=X-Request-Id, \d+# - Cookie=username,link# - Between=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai], 2024-11-07T09:08:00.797682100+08:00[America/Denver]#- Before=2024-11-07T09:05:00.797682100+08:00[America/Denver]#- After=2024-11-07T08:58:38.797682100+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/**              # 断言,路径相匹配的进行路由
9:Query Request Predicate(查询请求断言)

路由Query谓词工厂采用两个参数:一个必需参数param和一个可选参数regexp(Java 正则表达式)。以下示例配置查询路由谓词:

应用程序.yml

spring:cloud:gateway:mvc:routes:- id: query_routeuri: https://example.orgpredicates:- Query=green

修改9527YML

server:port: 9527spring:application:name: cloud-gateway #以微服务注册进consul或nacos服务列表内cloud:consul: #配置consul地址host: localhostport: 8500discovery:prefer-ip-address: trueservice-name: ${spring.application.name}gateway:routes:- id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:- Query=username, \d+#- Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由#- Method=GET,POST#- Host=**.atguigu.com#- Header=X-Request-Id, \d+# - Cookie=username,link# - Between=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai], 2024-11-07T09:08:00.797682100+08:00[America/Denver]#- Before=2024-11-07T09:05:00.797682100+08:00[America/Denver]#- After=2024-11-07T08:58:38.797682100+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/**              # 断言,路径相匹配的进行路由
10:Weight Request Predicate(权重请求断言)

路由Weight谓词工厂采用两个参数:groupweight(一个int)。权重按组计算。以下示例配置权重路由谓词:

应用程序.yml

spring:cloud:gateway:mvc:routes:- id: weight_highuri: https://weighthigh.orgpredicates:- Weight=group1, 8- id: weight_lowuri: https://weightlow.orgpredicates:- Weight=group1, 2

该路由将把80%的流量转发到weightthigh.org,20%的流量转发到weightlow.org。

修改9527YML

server:port: 9527spring:application:name: cloud-gateway #以微服务注册进consul或nacos服务列表内cloud:consul: #配置consul地址host: localhostport: 8500discovery:prefer-ip-address: trueservice-name: ${spring.application.name}gateway:routes:- id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:- Weight=group1, 2#- Query=username, \d+#- Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由#- Method=GET,POST#- Host=**.atguigu.com#- Header=X-Request-Id, \d+# - Cookie=username,link# - Between=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai], 2024-11-07T09:08:00.797682100+08:00[America/Denver]#- Before=2024-11-07T09:05:00.797682100+08:00[America/Denver]#- After=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai]- id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:- Weight=group1, 8#- Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由
2)自定义断言,XXXRoutePredicateFactory规则

自定义模版:

  • 继承AbstractRoutePredicateFactory抽象类
  • 实现RoutePredicateFactory接口
  • 开头任意取名,但是必须以RoutePredicateFactory后缀结尾

编写步骤

1:新建MyRoutePredicateFactory类并继承AbstractRoutePredicateFactory类
package com.atguigu.cloud.config;import jakarta.validation.constraints.NotEmpty;
import lombok.Getter;
import lombok.Setter;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;import java.util.function.Predicate;/*** @ClassName MyRoutePredicateFactory* @Author link* @Date: 2024/11/7 上午10:10* @Version v1.0* @Description:*/
@Component
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config> {}
2:重写apply方法
package com.atguigu.cloud.config;import jakarta.validation.constraints.NotEmpty;
import lombok.Getter;
import lombok.Setter;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;import java.util.function.Predicate;/*** @ClassName MyRoutePredicateFactory* @Author link* @Date: 2024/11/7 上午10:10* @Version v1.0* @Description:*/
@Component
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config> {@Overridepublic Predicate<ServerWebExchange> apply(MyRoutePredicateFactory.Config config) {return null;}}
3:新建静态内部类Config方法
package com.atguigu.cloud.config;import jakarta.validation.constraints.NotEmpty;
import lombok.Getter;
import lombok.Setter;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;import java.util.function.Predicate;/*** @ClassName MyRoutePredicateFactory* @Author link* @Date: 2024/11/7 上午10:10* @Version v1.0* @Description:*/
@Component
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config> {@Overridepublic Predicate<ServerWebExchange> apply(MyRoutePredicateFactory.Config config) {return null;}@Validatedpublic static class Config {@Getter@Setter@NotEmptyprivate String userType;}
}
4:空参构造方法,内部调用super
package com.atguigu.cloud.config;import jakarta.validation.constraints.NotEmpty;
import lombok.Getter;
import lombok.Setter;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;import java.util.function.Predicate;/*** @ClassName MyRoutePredicateFactory* @Author link* @Date: 2024/11/7 上午10:10* @Version v1.0* @Description:*/
@Component
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config> {public MyRoutePredicateFactory() {super(Config.class);}@Overridepublic Predicate<ServerWebExchange> apply(MyRoutePredicateFactory.Config config) {return null;}@Validatedpublic static class Config {@Getter@Setter@NotEmptyprivate String userType;}
}
5:重写apply方法第二版
package com.atguigu.cloud.config;import jakarta.validation.constraints.NotEmpty;
import lombok.Getter;
import lombok.Setter;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;import java.util.function.Predicate;/*** @ClassName MyRoutePredicateFactory* @Author link* @Date: 2024/11/7 上午10:10* @Version v1.0* @Description:*/
@Component
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config> {public MyRoutePredicateFactory() {super(Config.class);}@Overridepublic Predicate<ServerWebExchange> apply(MyRoutePredicateFactory.Config config) {return new Predicate<ServerWebExchange>() {@Overridepublic boolean test(ServerWebExchange serverWebExchange) {//检查request的参数里面,userType是否为指定值,符合配置通过String userType = serverWebExchange.getRequest().getQueryParams().getFirst("userType");if (userType == null) {return false;}//如果参数存在则和config比较if(userType.equals(config.getUserType())){return true;}return false;}};}@Validatedpublic static class Config {@Getter@Setter@NotEmptyprivate String userType;}
}
6:实现shortcutFieldOrder方法,使其支持短格式
package com.atguigu.cloud.config;import jakarta.validation.constraints.NotEmpty;
import lombok.Getter;
import lombok.Setter;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;/*** @ClassName MyRoutePredicateFactory* @Author link* @Date: 2024/11/7 上午10:10* @Version v1.0* @Description:*/
@Component
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config> {//实现shortcutFieldOrder使其支持短格式写法@Overridepublic List<String> shortcutFieldOrder() {return Collections.singletonList("userType");}public MyRoutePredicateFactory() {super(Config.class);}@Overridepublic Predicate<ServerWebExchange> apply(MyRoutePredicateFactory.Config config) {return new Predicate<ServerWebExchange>() {@Overridepublic boolean test(ServerWebExchange serverWebExchange) {//检查request的参数里面,userType是否为指定值,符合配置通过String userType = serverWebExchange.getRequest().getQueryParams().getFirst("userType");if (userType == null) {return false;}//如果参数存在则和config比较if(userType.equals(config.getUserType())){return true;}return false;}};}@Validatedpublic static class Config {@Getter@Setter@NotEmptyprivate String userType;}
}
7:配置yml
server:port: 9527spring:application:name: cloud-gateway #以微服务注册进consul或nacos服务列表内cloud:consul: #配置consul地址host: localhostport: 8500discovery:prefer-ip-address: trueservice-name: ${spring.application.name}gateway:routes:- id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:- My=test#- Weight=group1, 2#- Query=username, \d+- Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由#- Method=GET,POST#- Host=**.atguigu.com#- Header=X-Request-Id, \d+# - Cookie=username,link# - Between=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai], 2024-11-07T09:08:00.797682100+08:00[America/Denver]#- Before=2024-11-07T09:05:00.797682100+08:00[America/Denver]#- After=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai]- id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:#- Weight=group1, 8- Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由
8:测试

在这里插入图片描述

在这里插入图片描述

3、Filter(过滤)

1)概述

过滤器分别会在请求被执行前调用或被执行后调用,用来修改请求和响应信息;

作用:

可以做请求鉴权,异常处理等;

类型:

  • 全局默认过滤器Global Filters:gateway出厂默认已有的,直接使用即可,主要作用于所有路由,不需要在配置文件中配置,只需实现GlobalFilter接口即可;
  • 单一内置过滤器GatewayFilter:也可以称为网关过滤器,这种过滤器主要作用于单一路由或者某个路由分组;
  • 自定义过滤器。
2)Gateway内置过滤器

单一内置过滤器GatewayFilter

1:请求头(RequestHeader)相关组

The AddRequestHeader GatewayFilter Factory(指定请求头内容ByName)

新增8001模块PayGateWayController方法

package com.atguigu.cloud.controller;import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.atguigu.cloud.entities.Pay;
import com.atguigu.cloud.resp.ResultData;
import com.atguigu.cloud.service.PayService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;import java.util.Enumeration;/*** @ClassName PayGateWayController* @Author link* @Date: 2024/11/6 下午3:56* @Version v1.0* @Description:*/
@RestController
public class PayGateWayController {@ResourcePayService payService;@GetMapping(value = "/pay/gateway/get/{id}")public ResultData<Pay> getById(@PathVariable("id") Integer id){Pay pay = payService.getById(id);return ResultData.success(pay);}@GetMapping(value = "/pay/gateway/info")public ResultData<String> getGatewayInfo(){return ResultData.success("gateway info test:"+ IdUtil.simpleUUID());}@GetMapping(value = "/pay/gateway/filter")public ResultData<String> getGatewayFilter(HttpServletRequest request){String result = "";Enumeration<String> headers = request.getHeaderNames();while(headers.hasMoreElements()){String headName = headers.nextElement();String headValue = request.getHeader(headName);System.out.println("请求头名: " + headName +"\t\t\t"+"请求头值: " + headValue);if(headName.equalsIgnoreCase("X-Request-atguigu1")|| headName.equalsIgnoreCase("X-Request-atguigu2")) {result = result+headName + "\t " + headValue +" ";}}return ResultData.success("getGatewayFilter 过滤器 test: "+result+" \t "+ DateUtil.now());}
}

修改9527yml文件

server:port: 9527spring:application:name: cloud-gateway #以微服务注册进consul或nacos服务列表内cloud:consul: #配置consul地址host: localhostport: 8500discovery:prefer-ip-address: trueservice-name: ${spring.application.name}gateway:routes:- id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:- My=test#- Weight=group1, 2#- Query=username, \d+- Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由#- Method=GET,POST#- Host=**.atguigu.com#- Header=X-Request-Id, \d+# - Cookie=username,link# - Between=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai], 2024-11-07T09:08:00.797682100+08:00[America/Denver]#- Before=2024-11-07T09:05:00.797682100+08:00[America/Denver]#- After=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai]- id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:#- Weight=group1, 8- Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由- id: pay_routh3 #pay_routh3uri: lb://cloud-payment-service                #匹配后提供服务的路由地址predicates:- Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由filters:- AddRequestHeader=X-Request-atguigu1,atguiguValue1  # 请求头kv,若一头含有多参则重写一行设置- AddRequestHeader=X-Request-atguigu2,atguiguValue2

测试:

在这里插入图片描述

The RemoveRequestHeader GatewayFilter Factory (删除请求头Byname)

以删除sec-fetch-site为例

在这里插入图片描述

修改9527yml文件

server:port: 9527spring:application:name: cloud-gateway #以微服务注册进consul或nacos服务列表内cloud:consul: #配置consul地址host: localhostport: 8500discovery:prefer-ip-address: trueservice-name: ${spring.application.name}gateway:routes:- id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:- My=test#- Weight=group1, 2#- Query=username, \d+- Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由#- Method=GET,POST#- Host=**.atguigu.com#- Header=X-Request-Id, \d+# - Cookie=username,link# - Between=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai], 2024-11-07T09:08:00.797682100+08:00[America/Denver]#- Before=2024-11-07T09:05:00.797682100+08:00[America/Denver]#- After=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai]- id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:#- Weight=group1, 8- Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由- id: pay_routh3 #pay_routh3uri: lb://cloud-payment-service                #匹配后提供服务的路由地址predicates:- Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由filters:- AddRequestHeader=X-Request-atguigu1,atguiguValue1  # 请求头kv,若一头含有多参则重写一行设置- AddRequestHeader=X-Request-atguigu2,atguiguValue2- RemoveRequestHeader=sec-fetch-site      # 删除请求头sec-fetch-site

测试:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

The SetRequestHeader GatewayFilter Factory (修改请求头Byname)

以sec-fetch-mode为例:
在这里插入图片描述

修改9527yml文件

server:port: 9527spring:application:name: cloud-gateway #以微服务注册进consul或nacos服务列表内cloud:consul: #配置consul地址host: localhostport: 8500discovery:prefer-ip-address: trueservice-name: ${spring.application.name}gateway:routes:- id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:- My=test#- Weight=group1, 2#- Query=username, \d+- Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由#- Method=GET,POST#- Host=**.atguigu.com#- Header=X-Request-Id, \d+# - Cookie=username,link# - Between=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai], 2024-11-07T09:08:00.797682100+08:00[America/Denver]#- Before=2024-11-07T09:05:00.797682100+08:00[America/Denver]#- After=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai]- id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:#- Weight=group1, 8- Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由- id: pay_routh3 #pay_routh3uri: lb://cloud-payment-service                #匹配后提供服务的路由地址predicates:- Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由filters:- AddRequestHeader=X-Request-atguigu1,atguiguValue1  # 请求头kv,若一头含有多参则重写一行设置- AddRequestHeader=X-Request-atguigu2,atguiguValue2- RemoveRequestHeader=sec-fetch-site      # 删除请求头sec-fetch-site- SetRequestHeader=sec-fetch-mode, Blue-updatebylink # 将请求头sec-fetch-mode对应的值修改为Blue-updatebylink

测试:

在这里插入图片描述

2:请求参数(RequestParameter)相关组

The AddRequestParameter GatewayFilter Factory(添加请求参数) 和 The RemoveRequestParameter GatewayFilter Factory(拦截请求参数)

修改9527yml文件

server:port: 9527spring:application:name: cloud-gateway #以微服务注册进consul或nacos服务列表内cloud:consul: #配置consul地址host: localhostport: 8500discovery:prefer-ip-address: trueservice-name: ${spring.application.name}gateway:routes:- id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:- My=test#- Weight=group1, 2#- Query=username, \d+- Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由#- Method=GET,POST#- Host=**.atguigu.com#- Header=X-Request-Id, \d+# - Cookie=username,link# - Between=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai], 2024-11-07T09:08:00.797682100+08:00[America/Denver]#- Before=2024-11-07T09:05:00.797682100+08:00[America/Denver]#- After=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai]- id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:#- Weight=group1, 8- Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由- id: pay_routh3 #pay_routh3uri: lb://cloud-payment-service                #匹配后提供服务的路由地址predicates:- Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由filters:- AddRequestHeader=X-Request-atguigu1,atguiguValue1  # 请求头kv,若一头含有多参则重写一行设置- AddRequestHeader=X-Request-atguigu2,atguiguValue2- RemoveRequestHeader=sec-fetch-site      # 删除请求头sec-fetch-site- SetRequestHeader=sec-fetch-mode, Blue-updatebylink # 将请求头sec-fetch-mode对应的值修改为Blue-updatebylink- AddRequestParameter=customerId,9527001 # 新增请求参数Parameter:k ,v- RemoveRequestParameter=customerName   # 删除url请求参数customerName,你传递过来也是null

修改PayGateWayController方法

package com.atguigu.cloud.controller;import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.atguigu.cloud.entities.Pay;
import com.atguigu.cloud.resp.ResultData;
import com.atguigu.cloud.service.PayService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;import java.util.Enumeration;/*** @ClassName PayGateWayController* @Author link* @Date: 2024/11/6 下午3:56* @Version v1.0* @Description:*/
@RestController
public class PayGateWayController {@ResourcePayService payService;@GetMapping(value = "/pay/gateway/get/{id}")public ResultData<Pay> getById(@PathVariable("id") Integer id){Pay pay = payService.getById(id);return ResultData.success(pay);}@GetMapping(value = "/pay/gateway/info")public ResultData<String> getGatewayInfo(){return ResultData.success("gateway info test:"+ IdUtil.simpleUUID());}@GetMapping(value = "/pay/gateway/filter")public ResultData<String> getGatewayFilter(HttpServletRequest request){String result = "";Enumeration<String> headers = request.getHeaderNames();while(headers.hasMoreElements()){String headName = headers.nextElement();String headValue = request.getHeader(headName);System.out.println("请求头名: " + headName +"\t\t\t"+"请求头值: " + headValue);if(headName.equalsIgnoreCase("X-Request-atguigu1")|| headName.equalsIgnoreCase("X-Request-atguigu2")) {result = result+headName + "\t " + headValue +" ";}}//请求参数System.out.println("=============================================");String customerId = request.getParameter("customerId");System.out.println("request Parameter customerId: "+customerId);String customerName = request.getParameter("customerName");System.out.println("request Parameter customerName: "+customerName);System.out.println("=============================================");return ResultData.success("getGatewayFilter 过滤器 test: "+result+" \t "+ DateUtil.now());}
}

测试:

1、访问http://localhost:9527/pay/gateway/filter 测试添加请求参数

在这里插入图片描述

2、访问http://localhost:9527/pay/gateway/filter?customerId=99999&customerName=link

可以发现customerId的值会发生变化,customerName还是null,说明被拦截

在这里插入图片描述

3:回应头(ResponseHeader)相关组

The AddResponseHeader GatewayFilter Factory (增加响应头参数)、The SetResponseHeader GatewayFilter Factory(修改响应头参数)和The RemoveResponseHeader GatewayFilter Factory(删除响应头参数)

设置前浏览器响应头:

在这里插入图片描述

修改9527yml文件

server:port: 9527spring:application:name: cloud-gateway #以微服务注册进consul或nacos服务列表内cloud:consul: #配置consul地址host: localhostport: 8500discovery:prefer-ip-address: trueservice-name: ${spring.application.name}gateway:routes:- id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:- My=test#- Weight=group1, 2#- Query=username, \d+- Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由#- Method=GET,POST#- Host=**.atguigu.com#- Header=X-Request-Id, \d+# - Cookie=username,link# - Between=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai], 2024-11-07T09:08:00.797682100+08:00[America/Denver]#- Before=2024-11-07T09:05:00.797682100+08:00[America/Denver]#- After=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai]- id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:#- Weight=group1, 8- Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由- id: pay_routh3 #pay_routh3uri: lb://cloud-payment-service                #匹配后提供服务的路由地址predicates:- Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由filters:- AddRequestHeader=X-Request-atguigu1,atguiguValue1  # 请求头kv,若一头含有多参则重写一行设置- AddRequestHeader=X-Request-atguigu2,atguiguValue2- RemoveRequestHeader=sec-fetch-site      # 删除请求头sec-fetch-site- SetRequestHeader=sec-fetch-mode, Blue-updatebylink # 将请求头sec-fetch-mode对应的值修改为Blue-updatebylink- AddRequestParameter=customerId,9527001 # 新增请求参数Parameter:k ,v- RemoveRequestParameter=customerName   # 删除url请求参数customerName,你传递过来也是null- AddResponseHeader=X-Response-link, testResponse # 新增请求参数X-Response-link并设值为testResponse- SetResponseHeader=Date,2099-11-11 # 设置回应头Date值为2099-11-11- RemoveResponseHeader=Content-Type # 将默认自带Content-Type回应属性删除

测试:

在这里插入图片描述

4:前缀和路径相关组

The PrefixPath GatewayFilter Factory (自动添加路径前缀)

之前正确访问地址:http://localhost:9527/pay/gateway/filter

修改之后访问地址:http://localhost:9527/gateway/filter

/pay前缀由过滤器统一管理

修改9527yml

server:port: 9527spring:application:name: cloud-gateway #以微服务注册进consul或nacos服务列表内cloud:consul: #配置consul地址host: localhostport: 8500discovery:prefer-ip-address: trueservice-name: ${spring.application.name}gateway:routes:- id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:- My=test#- Weight=group1, 2#- Query=username, \d+- Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由#- Method=GET,POST#- Host=**.atguigu.com#- Header=X-Request-Id, \d+# - Cookie=username,link# - Between=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai], 2024-11-07T09:08:00.797682100+08:00[America/Denver]#- Before=2024-11-07T09:05:00.797682100+08:00[America/Denver]#- After=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai]- id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:#- Weight=group1, 8- Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由- id: pay_routh3 #pay_routh3uri: lb://cloud-payment-service                #匹配后提供服务的路由地址predicates:# - Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由- Path=/gateway/filter/**   # 断言,为配合PrefixPath测试过滤,暂时注释掉/payfilters:- AddRequestHeader=X-Request-atguigu1,atguiguValue1  # 请求头kv,若一头含有多参则重写一行设置- AddRequestHeader=X-Request-atguigu2,atguiguValue2- RemoveRequestHeader=sec-fetch-site      # 删除请求头sec-fetch-site- SetRequestHeader=sec-fetch-mode, Blue-updatebylink # 将请求头sec-fetch-mode对应的值修改为Blue-updatebylink- AddRequestParameter=customerId,9527001 # 新增请求参数Parameter:k ,v- RemoveRequestParameter=customerName   # 删除url请求参数customerName,你传递过来也是null- AddResponseHeader=X-Response-link, testResponse # 新增请求参数X-Response-link并设值为testResponse- SetResponseHeader=Date,2099-11-11 # 设置回应头Date值为2099-11-11- RemoveResponseHeader=Content-Type # 将默认自带Content-Type回应属性删除- PrefixPath=/pay # http://localhost:9527/pay/gateway/filter 隐藏的前缀

测试:

在这里插入图片描述

The SetPath GatewayFilter Factory (访问路径修改)

浏览器访问地址: http://localhost:9527/XYZ/abc/filter

实际微服务地址:http://localhost:9527/pay/gateway/filter

修改9527yml

server:port: 9527spring:application:name: cloud-gateway #以微服务注册进consul或nacos服务列表内cloud:consul: #配置consul地址host: localhostport: 8500discovery:prefer-ip-address: trueservice-name: ${spring.application.name}gateway:routes:- id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:- My=test#- Weight=group1, 2#- Query=username, \d+- Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由#- Method=GET,POST#- Host=**.atguigu.com#- Header=X-Request-Id, \d+# - Cookie=username,link# - Between=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai], 2024-11-07T09:08:00.797682100+08:00[America/Denver]#- Before=2024-11-07T09:05:00.797682100+08:00[America/Denver]#- After=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai]- id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:#- Weight=group1, 8- Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由- id: pay_routh3 #pay_routh3uri: 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-updatebylink # 将请求头sec-fetch-mode对应的值修改为Blue-updatebylink
#            - AddRequestParameter=customerId,9527001 # 新增请求参数Parameter:k ,v
#            - RemoveRequestParameter=customerName   # 删除url请求参数customerName,你传递过来也是null
#            - AddResponseHeader=X-Response-link, testResponse # 新增请求参数X-Response-link并设值为testResponse
#            - 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也行但要上下一致

测试:

在这里插入图片描述

The RedirectTo GatewayFilter Factory (重定向到某个页面)

修改9527yml

server:port: 9527spring:application:name: cloud-gateway #以微服务注册进consul或nacos服务列表内cloud:consul: #配置consul地址host: localhostport: 8500discovery:prefer-ip-address: trueservice-name: ${spring.application.name}gateway:routes:- id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:- My=test#- Weight=group1, 2#- Query=username, \d+- Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由#- Method=GET,POST#- Host=**.atguigu.com#- Header=X-Request-Id, \d+# - Cookie=username,link# - Between=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai], 2024-11-07T09:08:00.797682100+08:00[America/Denver]#- Before=2024-11-07T09:05:00.797682100+08:00[America/Denver]#- After=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai]- id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:#- Weight=group1, 8- Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由- id: pay_routh3 #pay_routh3uri: lb://cloud-payment-service                #匹配后提供服务的路由地址predicates:# - Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由# - Path=/gateway/filter/**   # 断言,为配合PrefixPath测试过滤,暂时注释掉/pay#- Path=/XYZ/abc/{segment}           # 断言,为配合SetPath测试,{segment}的内容最后被SetPath取代- Path=/pay/gateway/filter/** # 真实地址filters:
#            - AddRequestHeader=X-Request-atguigu1,atguiguValue1  # 请求头kv,若一头含有多参则重写一行设置
#            - AddRequestHeader=X-Request-atguigu2,atguiguValue2
#            - RemoveRequestHeader=sec-fetch-site      # 删除请求头sec-fetch-site
#            - SetRequestHeader=sec-fetch-mode, Blue-updatebylink # 将请求头sec-fetch-mode对应的值修改为Blue-updatebylink
#            - AddRequestParameter=customerId,9527001 # 新增请求参数Parameter:k ,v
#            - RemoveRequestParameter=customerName   # 删除url请求参数customerName,你传递过来也是null
#            - AddResponseHeader=X-Response-link, testResponse # 新增请求参数X-Response-link并设值为testResponse
#            - 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, http://www.baidu.com/ # 访问http://localhost:9527/pay/gateway/filter跳转到http://www.baidu.com/
5:其他

Default Filters

配置在此处相当于全局通用,自定义秒变Global

spring:cloud:gateway:default-filters:-AddResponseHeader-X-Response-Default-Red,Default-Blue-PrefixPath=/httpbin
3)Gateway自定义过滤器
1:自定义全局Filter

案例:统计接口调用耗时情况

自定义接口调用耗时统计全局过滤器

(1)新建类MyGlobalFilter并实现GlobalFilter,Ordered两个接口

package com.atguigu.cloud.config;import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;/*** @ClassName MyGlobalFilter* @Author link* @Date: 2024/11/7 下午3:15* @Version v1.0* @Description:*/
@Component
@Slf4j
public class MyGlobalFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {return null;}@Overridepublic int getOrder() {return 0;}
}

(2)修改YML

server:port: 9527spring:application:name: cloud-gateway #以微服务注册进consul或nacos服务列表内cloud:consul: #配置consul地址host: localhostport: 8500discovery:prefer-ip-address: trueservice-name: ${spring.application.name}gateway:routes:- id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:
#            - My=test#- Weight=group1, 2#- Query=username, \d+- Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由#- Method=GET,POST#- Host=**.atguigu.com#- Header=X-Request-Id, \d+# - Cookie=username,link# - Between=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai], 2024-11-07T09:08:00.797682100+08:00[America/Denver]#- Before=2024-11-07T09:05:00.797682100+08:00[America/Denver]#- After=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai]- id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:#- Weight=group1, 8- Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由- id: pay_routh3 #pay_routh3uri: lb://cloud-payment-service                #匹配后提供服务的路由地址predicates:- Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由# - Path=/gateway/filter/**   # 断言,为配合PrefixPath测试过滤,暂时注释掉/pay#- Path=/XYZ/abc/{segment}           # 断言,为配合SetPath测试,{segment}的内容最后被SetPath取代
#            - Path=/pay/gateway/filter/** # 真实地址filters:
#            - AddRequestHeader=X-Request-atguigu1,atguiguValue1  # 请求头kv,若一头含有多参则重写一行设置
#            - AddRequestHeader=X-Request-atguigu2,atguiguValue2
#            - RemoveRequestHeader=sec-fetch-site      # 删除请求头sec-fetch-site
#            - SetRequestHeader=sec-fetch-mode, Blue-updatebylink # 将请求头sec-fetch-mode对应的值修改为Blue-updatebylink
#            - AddRequestParameter=customerId,9527001 # 新增请求参数Parameter:k ,v
#            - RemoveRequestParameter=customerName   # 删除url请求参数customerName,你传递过来也是null
#            - AddResponseHeader=X-Response-link, testResponse # 新增请求参数X-Response-link并设值为testResponse
#            - 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, http://www.baidu.com/ # 访问http://localhost:9527/pay/gateway/filter跳转到http://www.baidu.com/

(3)MyGlobalFilter 实现

package com.atguigu.cloud.config;import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;/*** @ClassName MyGlobalFilter* @Author link* @Date: 2024/11/7 下午3:15* @Version v1.0* @Description:*/
@Component
@Slf4j
public class MyGlobalFilter implements GlobalFilter, Ordered {private static final String BEGIN_VISIT_TIME = "beginVisitTime";@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {//先记录下访问接口的时间exchange.getAttributes().put(BEGIN_VISIT_TIME, System.currentTimeMillis());return chain.filter(exchange).then(Mono.fromRunnable(()->{Long beginVisitTime = exchange.getAttribute(BEGIN_VISIT_TIME);if(beginVisitTime != null){log.info("访问接口主机: " + exchange.getRequest().getURI().getHost());log.info("访问接口端口: " + exchange.getRequest().getURI().getPort());log.info("访问接口URL: " + exchange.getRequest().getURI().getPath());log.info("访问接口URL参数: " + exchange.getRequest().getURI().getRawQuery());log.info("访问接口时长: " + (System.currentTimeMillis() - beginVisitTime) + "ms");log.info("我是美丽分割线: ###################################################");System.out.println();}}));}/**** 数字越小优先级越高**/@Overridepublic int getOrder() {return 0;}
}

测试:

分别访问:http://localhost:9527/pay/gateway/get/1

http://localhost:9527/pay/gateway/info

http://localhost:9527/pay/gateway/filter

在这里插入图片描述

2:自定义条件Filter

(1)新建类名MyGatewayFilterFactory需要以GatewayFilterFactory结尾并继承AbstractGatewayFilterFactory类

package com.atguigu.cloud.config;import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.stereotype.Component;/*** @ClassName MyGatewayFilterFactory* @Author link* @Date: 2024/11/7 下午3:31* @Version v1.0* @Description:*/
@Component
public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.Config> {
}

(2)新建MyGatewayFilterFactory.Config类

package com.atguigu.cloud.config;import lombok.Getter;
import lombok.Setter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.stereotype.Component;/*** @ClassName MyGatewayFilterFactory* @Author link* @Date: 2024/11/7 下午3:31* @Version v1.0* @Description:*/
@Component
public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.Config> {public static class Config{@Setter@Getterprivate String status;}
}

(3)重写apply方法

package com.atguigu.cloud.config;import lombok.Getter;
import lombok.Setter;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;/*** @ClassName MyGatewayFilterFactory* @Author link* @Date: 2024/11/7 下午3:31* @Version v1.0* @Description:*/
@Component
public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.Config> {@Overridepublic GatewayFilter apply(Config config) {return new GatewayFilter() {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();System.out.println("进入自定义网关过滤器MyGatewayFilterFactory,status===="+config.getStatus());if (request.getQueryParams().containsKey("link")){return chain.filter(exchange);}else {exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);return exchange.getResponse().setComplete();}}};}public static class Config{@Setter@Getterprivate String status;}
}

(4)重写shortcutFieldOrder

package com.atguigu.cloud.config;import lombok.Getter;
import lombok.Setter;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;import java.util.ArrayList;
import java.util.List;/*** @ClassName MyGatewayFilterFactory* @Author link* @Date: 2024/11/7 下午3:31* @Version v1.0* @Description:*/
@Component
public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.Config> {@Overridepublic List<String> shortcutFieldOrder() {List<String> list = new ArrayList<String>();list.add("status");return list;}@Overridepublic GatewayFilter apply(Config config) {return new GatewayFilter() {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();System.out.println("进入自定义网关过滤器MyGatewayFilterFactory,status===="+config.getStatus());if (request.getQueryParams().containsKey("link")){return chain.filter(exchange);}else {exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);return exchange.getResponse().setComplete();}}};}public static class Config{@Setter@Getterprivate String status;}
}

(5)空参构造方法,内部调用super

package com.atguigu.cloud.config;import lombok.Getter;
import lombok.Setter;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;import java.util.ArrayList;
import java.util.List;/*** @ClassName MyGatewayFilterFactory* @Author link* @Date: 2024/11/7 下午3:31* @Version v1.0* @Description:*/
@Component
public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.Config> {public MyGatewayFilterFactory() {super(MyGatewayFilterFactory.Config.class);}@Overridepublic List<String> shortcutFieldOrder() {List<String> list = new ArrayList<String>();list.add("status");return list;}@Overridepublic GatewayFilter apply(Config config) {return new GatewayFilter() {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();System.out.println("进入自定义网关过滤器MyGatewayFilterFactory,status===="+config.getStatus());if (request.getQueryParams().containsKey("link")){return chain.filter(exchange);}else {exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);return exchange.getResponse().setComplete();}}};}public static class Config{@Setter@Getterprivate String status;}
}

(6)配置YML

server:port: 9527spring:application:name: cloud-gateway #以微服务注册进consul或nacos服务列表内cloud:consul: #配置consul地址host: localhostport: 8500discovery:prefer-ip-address: trueservice-name: ${spring.application.name}gateway:routes:- id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:
#            - My=test#- Weight=group1, 2#- Query=username, \d+- Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由#- Method=GET,POST#- Host=**.atguigu.com#- Header=X-Request-Id, \d+# - Cookie=username,link# - Between=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai], 2024-11-07T09:08:00.797682100+08:00[America/Denver]#- Before=2024-11-07T09:05:00.797682100+08:00[America/Denver]#- After=2024-11-07T08:58:38.797682100+08:00[Asia/Shanghai]- id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001                #匹配后提供服务的路由地址uri: lb://cloud-payment-service            #匹配后提供服务名称predicates:#- Weight=group1, 8- Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由- id: pay_routh3 #pay_routh3uri: lb://cloud-payment-service                #匹配后提供服务的路由地址predicates:- Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由# - Path=/gateway/filter/**   # 断言,为配合PrefixPath测试过滤,暂时注释掉/pay#- Path=/XYZ/abc/{segment}           # 断言,为配合SetPath测试,{segment}的内容最后被SetPath取代
#            - Path=/pay/gateway/filter/** # 真实地址filters:- My=link
#            - AddRequestHeader=X-Request-atguigu1,atguiguValue1  # 请求头kv,若一头含有多参则重写一行设置
#            - AddRequestHeader=X-Request-atguigu2,atguiguValue2
#            - RemoveRequestHeader=sec-fetch-site      # 删除请求头sec-fetch-site
#            - SetRequestHeader=sec-fetch-mode, Blue-updatebylink # 将请求头sec-fetch-mode对应的值修改为Blue-updatebylink
#            - AddRequestParameter=customerId,9527001 # 新增请求参数Parameter:k ,v
#            - RemoveRequestParameter=customerName   # 删除url请求参数customerName,你传递过来也是null
#            - AddResponseHeader=X-Response-link, testResponse # 新增请求参数X-Response-link并设值为testResponse
#            - 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, http://www.baidu.com/ # 访问http://localhost:9527/pay/gateway/filter跳转到http://www.baidu.com/

(7)测试

在这里插入图片描述

在这里插入图片描述

相关文章:

07-SpringCloud-Gateway新一代网关

一、概述 1、Gateway介绍 官网&#xff1a;https://spring.io/projects/spring-cloud-gateway Spring Cloud Gateway组件的核心是一系列的过滤器&#xff0c;通过这些过滤器可以将客户端发送的请求转发(路由)到对应的微服务。 Spring Cloud Gateway是加在整个微服务最前沿的防…...

HTML 表单实战:从创建到验证

HTML表单是用于收集用户输入数据的一种方式&#xff0c;可以用于创建各种类型的表单&#xff0c;例如登录表单、注册表单、调查问卷表单等。本文将详细介绍表单元素的使用&#xff0c;并利用JavaScript实现对表单数据的验证。 HTML表单元素的使用 输入框<input> <i…...

【redis 】string类型详解

string类型详解 一、string类型的概念二、string类型的常用指令2.1 SET2.2 GET2.3 MSET2.4 MGET2.5 SETNX2.6 INCR2.7 INCRBY2.8 DECR2.9 DECRBY2.10 INCRBYFLOAT2.11 APPEND2.12 GETRANGE2.13 SETRANGE2.14 STRLEN 三、string类型的命令小结四、string类型的内部编码五、strin…...

Vue.js 学习总结(13)—— Vue3 version 计数介绍

前言 Vue3.5 提出了两个重要概念&#xff1a;version计数和双向链表&#xff0c;作为在内存和计算方面性能提升的最大功臣。既然都重要&#xff0c;那就单挑 version 计数来介绍&#xff0c;它在依赖追踪过程中&#xff0c;起到快速判断依赖项有没有更新的作用&#xff0c;所以…...

【数据结构】【线性表】一文讲完队列(附C语言源码)

队列 队列的基本概念基本术语基本操作 队列的顺序实现顺序队列结构体的创建顺序队列的初始化顺序队列入队顺序队列出队顺序队列存在的问题分析循环队列代码汇总 队列的链式实现链式队列的创建链式队列初始化-不带头结点链式队列入队-不带头节点链式队列出队-不带头结点带头结点…...

2024年11月最新 Alfred 5 Powerpack (MACOS)下载

在现代数字化办公中&#xff0c;我们常常被繁杂的任务所包围&#xff0c;而时间的高效利用成为一项核心需求。Alfred 5 Powerpack 是一款专为 macOS 用户打造的高效工作流工具&#xff0c;以其强大的定制化功能和流畅的用户体验&#xff0c;成为众多效率爱好者的首选。 点击链…...

ODBC连接PostgreSQL数据库后,网卡DOWN后,客户端进程阻塞问题解决方法

问题现象&#xff1a;数据库客户端进程数据库连接成功后&#xff0c;再把跟数据库交互的网卡down掉&#xff0c;客户端进程就会阻塞&#xff0c;无法进行其他处理。该问题跟TCP keepalive机制有关。 可以在odbc.ini文件中增加相应的属性来解决&#xff0c;在odbc.ini 增加如下…...

VsCode使用git提交很慢(一直显示在提交)_vscode commit很慢解决方法

VsCode使用git提交很慢&#xff08;一直显示在提交&#xff09;_vscode commit很慢...

linux从0到1——shell编程9

声明&#xff01; 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团队无关&a…...

计算机网络技术专业,热门就业方向和就业前景

前言 在数字化飞速发展的今天&#xff0c;计算机网络技术专业成为了众多学子和职场人士关注的焦点。这一专业不仅涵盖了计算机硬件、软件和网络通信等多个领域的知识&#xff0c;更在就业市场上展现出强大的竞争力。本文将带您一探计算机网络技术专业的就业方向和就业前景&…...

C++中定义类型名的方法

什么是 C 中的类型别名和 using 声明&#xff1f; 类型别名与using都是为了提高代码的可读性。 有两种方法可以定义类型别名 一种是使用关键字typedef起别名使用别名声明来定义类型的别名&#xff0c;即使用using. typedef 关键字typedef作为声明语句中的基本数据类型的一…...

从零开始学习 sg200x 多核开发之 camera-sensor 添加与测试

sg2002 集成了 H.264 视频压缩编解码器, H.265 视频压缩编码器和 ISP&#xff1b;支持 HDR 宽动态、3D 降噪、除雾、镜头畸变校正等多种图像增强和矫正算法。 sophpi 中没有提供相关图像 sensor。本次实验是在 milkv-duo256m 上添加 GC2083。 GC2083 格科微的 GC2083 是一款…...

前端三剑客(二):CSS

目录 1. CSS 基础 1.1 什么是 CSS 1.2 语法格式 1.3 引入方式 1.3.1 行内样式 1.3.2 内部样式 1.3.3 外部样式 1.4 CSS 编码规范 2. 选择器 2.1 标签选择器 2.2 id 选择器 2.3 class 选择器(类选择器) 2.4 复合选择器 2.5 通配符选择器 3. 常用 CSS 样式 3.1 c…...

国土变更调查拓扑错误自动化修复工具的研究

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 一、拓扑错误的形成原因 1.边界不一致 2.不规则图形 3.尖锐角 4.局部狭长 5.细小碎面 6.更新层相互重叠 二、修复成果展示 1.边界不一致 2.不规则图形 3.尖锐角 4.局部狭…...

深度学习图像视觉 RKNN Toolkit2 部署 RK3588S边缘端 过程全记录

深度学习图像视觉 RKNN Toolkit2 部署 RK3588S边缘端 过程全记录 认识RKNN Toolkit2 工程文件学习路线&#xff1a; Anaconda Miniconda安装.condarc 文件配置镜像源自定义conda虚拟环境路径创建Conda虚拟环境 本地训练环境本地转换环境安装 RKNN-Toolkit2&#xff1a;添加 lin…...

Linux应用编程(C语言编译过程)

目录 1. 举例 2.预处理 2.1 预处理命令 2.2 .i文件内容解读 3.编译 4.汇编 5.链接 5.1 链接方式 5.1.1 静态链接 5.1.2 动态链接 5.1.3 混合链接 1. 举例 Linux的C语言开发&#xff0c;一般选择GCC工具链进行编译&#xff0c;通过下面的例子来演示GCC如何使用&#…...

ssm实战项目──哈米音乐(二)

目录 1、流派搜索与分页 2、流派的添加 3、流派的修改 4、流派的删除 接上篇&#xff1a;ssm实战项目──哈米音乐&#xff08;一&#xff09;&#xff0c;我们完成了项目的整体搭建&#xff0c;接下来进行后台模块的开发。 首先是流派模块&#xff1a; 在该模块中采用分…...

Python 获取微博用户信息及作品(完整版)

在当今的社交媒体时代&#xff0c;微博作为一个热门的社交平台&#xff0c;蕴含着海量的用户信息和丰富多样的内容。今天&#xff0c;我将带大家深入了解一段 Python 代码&#xff0c;它能够帮助我们获取微博用户的基本信息以及下载其微博中的相关素材&#xff0c;比如图片等。…...

Flink学习连载第二篇-使用flink编写WordCount(多种情况演示)

使用Flink编写代码&#xff0c;步骤非常固定&#xff0c;大概分为以下几步&#xff0c;只要牢牢抓住步骤&#xff0c;基本轻松拿下&#xff1a; 1. env-准备环境 2. source-加载数据 3. transformation-数据处理转换 4. sink-数据输出 5. execute-执行 DataStream API开发 //n…...

拉格朗日乘子(Lagrange Multiplier)是数学分析中用于解决带有约束条件的优化问题的一种重要方法,特别是SVM

拉格朗日乘子&#xff08;Lagrange Multiplier&#xff09;是数学分析中用于解决带有约束条件的优化问题的一种重要方法&#xff0c;也称为拉格朗日乘数法。 例如之前博文写的2月7日 SVM&线性回归&逻辑回归在支持向量机&#xff08;SVM&#xff09;中&#xff0c;为了…...

鸿蒙征文|鸿蒙心路旅程:始于杭研所集训营,升华于横店

始于杭研所 在2024年7月&#xff0c;我踏上了一段全新的旅程&#xff0c;前往风景如画的杭州&#xff0c;参加华为杭研所举办的鲲鹏&昇腾集训营。这是一个专门为开发者设计的培训项目&#xff0c;中途深入学习HarmonyOS相关技术。对于我这样一个对技术充满热情的学生来说&…...

c语言数据结构与算法--简单实现线性表(顺序表+链表)的插入与删除

老规矩&#xff0c;点赞评论收藏关注&#xff01;&#xff01;&#xff01; 目录 线性表 其特点是&#xff1a; 算法实现&#xff1a; 运行结果展示 链表 插入元素&#xff1a; 删除元素&#xff1a; 算法实现 运行结果 线性表是由n个数据元素组成的有限序列&#xff…...

MySQL底层概述—1.InnoDB内存结构

大纲 1.InnoDB引擎架构 2.Buffer Pool 3.Page管理机制之Page页分类 4.Page管理机制之Page页管理 5.Change Buffer 6.Log Buffer 1.InnoDB引擎架构 (1)InnoDB引擎架构图 (2)InnoDB内存结构 (1)InnoDB引擎架构图 下面是InnoDB引擎架构图&#xff0c;主要分为内存结构和磁…...

MySQL:DATEDIFF()计算两个日期天数之差

题目需求&#xff1a; 计算出比前一天温度要高的日期。 select a.id from weather a, weather b where a.temperature > b.temperature and datediff(a.recordDate, b.recordDate) 1; DATEDIFF(date1, date2)函数用于计算两个日期之间的天数差。函数返回date1和date2之…...

Linux 编译Ubuntu24内核

参考来源&#xff1a; 编译并更新内核&#xff1a;https://www.cnblogs.com/smlile-you-me/p/18248433 编译报错–sub-make: https://forum.linuxfoundation.org/discussion/865005/facing-error-in-building-the-kernel 1.下载源码,执行如下命令&#xff0c;会在/usr/src下多…...

Android系统中init进程、zygote进程和SystemServer进程简单学习总结

Android系统中&#xff0c;init、zygote和SystemServer进程是系统启动和运行的关键进程&#xff0c;它们之间有着密切的关系&#xff0c;本文针对这三个进程的学习做一个简单汇总&#xff0c;方便后续查询。 1、init进程 Android用户空间执行的第一个程序就是它&#xff0c;可…...

Flask 基于wsgi源码启动流程

1. 点击 __call__ 进入到源码 2. 找到 __call__ 方法 return 执行的是 wsgi方法 3. 点击 wsgi 方法 进到 wsgi return 执行的是 response 方法 4. 点击response 方法 进到 full_dispatch_request 5. full_dispatch_request 执行finalize_request 方法 6. finalize_request …...

leetcode代码 50道答案

‌简单难度&#xff1a;两数之和 def twoSum(nums, target): for i in range(len(nums)): for j in range(i 1, len(nums)): if nums[i] nums[j] target: return [i, j] return [] 简单难度&#xff1a;有效的括号 def isVa…...

Centos-stream 9,10 add repo

Centos-stream repo前言 Centos-stream 9,10更换在线阿里云创建一键更换repo 自动化脚本 华为centos-stream 源 , 阿里云centos-stream 源 华为epel 源 , 阿里云epel 源vim /centos9_10_repo.sh #!/bin/bash # -*- coding: utf-8 -*- # Author: make.h...

【隐私计算大模型】联邦深度学习之拆分学习Split learning原理及安全风险、应对措施以及在大模型联合训练中的应用案例

Tips&#xff1a;在两方场景下&#xff0c;设计的安全算法&#xff0c;如果存在信息不对等性&#xff0c;那么信息获得更多的一方可以有概率对另一方实施安全性攻击。 1. 拆分学习原理 本文介绍了一种适用于隐私计算场景的深度学习实现方案——拆分学习&#xff0c;又称分割…...