【SpringCloud】6.gateway——网关

前面学了openFeign(https://www.cnblogs.com/luyj00436/p/18588116),负责服务发现和负载均衡。

gateway : 网关 (对外)
openFeign 对内

SpringCloud Gateway本身也是一个微服务。需要注册服务中心进行注册。

概述

Spring Cloud gateway官网地址:https://docs.spring.io/spring-cloud-gateway/docs/4.0.4/reference/html/

为了统一管理微服务和安全,要使用网关。

微服务网关定位

Cloud全家桶中有个很重要的组件就是网关,在1.x版本中都是采用的Zuul网关;

但在2.x版本中,zuul的升级一直跳票,SpringCloud最后自己研发了一个网关SpringCloud Gateway替代Zuul。

网关的作用:

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

Gateway的三大核心

Web前端请求,通过一些匹配条件,定位到真正的服务节点。在这个转发过程的前后,会进行一些精细化的控制。predicate就是我们的匹配条件;filter,可以理解为无所不能的拦截器。有了这两个元素,加上目标url,就可以实现具体的路由了。

  • Route(路由),路由是构建网关的基本模块,它有ID,目标URL,一系列的断言和过滤器组成,如果断言为true,则匹配该路由。
  • Predicate(断言)
  • Filter(过滤),使用GatewayFilter过滤器,可以对请求前后进行修改。

后文的高级特性中,会更具体的讲到这三大核心的使用。

注:Gateway本身也是微服务

入门配置

建Mondule,建立一个子模块cloud-gateway9527

改POM, 为新建的子模块cloud-gateway9527 添加服务依赖(添加网关、consul)

<!--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>

写YML,将依赖注入consual

<!--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>

主启动:

@SpringBootApplication
@EnableDiscoveryClient //服务注册和发现
public class Main9527
{
    public static void main(String[] args)
    {
        SpringApplication.run(Main9527.class,args);
    }
}

测试

先启动8500服务中心Consul,在启动9527网关入驻。
image

网关做路由映射

目前,假设现在不想对外暴露8001端口。希望在8001端口外套一层9527。

例子

这里我们在8001端口对应的模块(cloud-provider-payment-8001)新增测试类:

@RestController
public class PayGateWayController {
    @Autowired
    PayServiceImpl payService;

    @GetMapping(value = "/pay/gateway/get/{id}")
    public ResultData<Pay> getPayId(@PathVariable("id") Integer id) {
        return ResultData.success(payService.getById(id));
    }

    @GetMapping(value = "/pay/gateway/info")
    public ResultData<String> getGatewayInfo(){
        return ResultData.success("/gateway info:" + IdUtil.simpleUUID());
    }
}

启动8001,测试自测通过。

网关9527,写YAML,新增8001的配置。

注:匹配路由的地址直接用端口号8001,并不利于维护。建议配合服务名,这里只是为了入门演示

spring:
  cloud:
    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/**              # 断言,路径相匹配的进行路由

启动8500/8001支付端口,网关9527端口后,可以通过:http://localhost:9527/pay/gateway/get/1 访问真实的接口: http://localhost:8001/pay/gateway/info

同一个公司,系统内环境,直接找微服务

不同公司,系统外访问,先网关再服务

GateWay高级特性

Router 动态微服务名称

前面的例子,URL地址写死,端口变更。好可怕😨。路由地址的格式可以:spring.cloud.gateway.routes.url:lb://service ,lb:// + 服务名。

spring:
  cloud:
    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/**              # 断言,路径相匹配的进行路由

此时,访问网关仍然能访问。修改被调用的服务端口,也不受影响。

断言(谓语)

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

启动网关后,查看后台:
image

断言有两种语法配置:Shortcut Configuration 和 Fully Expanded Arguments。后续例子使用的是Shortcut 配置。
image
image

接下来,我们可以依据官网,学习断言的使用,先看第一个例子,After
image

这个时间格式?2017-01-20T17:42:47.789-07:00[America/Denver]是什么?是包含时区的日期时间格式。可以使用代码ZonedDateTime.now();获取。

常用断言api如下:

  • After : 指定日期时间后发生请求
  • Before :指定日期时间前发生请求
  • Between: 指定日期时间之间发生请求
  • Cookie: 包含Cookie断言
  • Header : 包含头Header断言
  • Host: host标头匹配断言
  • Method: 方法断言,例如固定只能GET、POST请求
  • Path: 路径断言,路由想匹配
  • Query:查询断言,支持两个参数:属性名和属性值,属性值可以为正则表达式
  • RemoteAddr:外部访问的IP限制

当然,如果常见断言不能满足我们的要求。我们可以进行自定义断言。

接下来,我们配置和使用断言。测试地址,为前文网关映射的正确地址测试:http://localhost:9527/pay/gateway/get/1

After 指定日期后发起请求

我们可以根据zonedDateTime ,获取日期时间格式。

写YAML,如下:

spring:
  cloud:
    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-12-30T10:28:00.231002700+08:00[Asia/Shanghai]

设置断言后,After参数的时间之前,请求返回404:

{
    "timestamp": "2024-12-30T02:27:14.504+00:00",
    "path": "/pay/gateway/get/1",
    "status": 404,
    "error": "Not Found",
    "requestId": "f85bffd7-5"
}

After时间后,请求调用正确的微服务dia调用结果:

{
    "code": "200",
    "message": "success",
    "data": {
        "id": 1,
        "payNo": "pay17203699",
        "orderNo": "6544bafb424a",
        "userId": 1,
        "amount": 9.90,
        "deleted": 0,
        "createTime": "2024-11-26 15:13:02",
        "updateTime": "2024-11-26 15:13:02"
    },
    "timestamp": 1735525896520
}

Before

同理,before表示时间前可以发起请求

spring:
  cloud:
    gateway:
      routes:
        - id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
#          uri: http://localhost:8001                #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service               #匹配后提供服务的路由地址
          predicates:
            - Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由
			- Before=2024-12-30T10:36:00.231002700+08:00[Asia/Shanghai]

Between

spring:
  cloud:
    gateway:
      routes:
        - id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
#          uri: http://localhost:8001                #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service               #匹配后提供服务的路由地址
          predicates:
            - Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由
			- Between=2024-12-30T10:36:00.231002700+08:00[Asia/Shanghai],2024-12-30T10:42:00.231002700+08:00[Asia/Shanghai]

包含Cookie的断言

spring:
  cloud:
    gateway:
      routes:
        - id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
#          uri: http://localhost:8001                #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service               #匹配后提供服务的路由地址
          predicates:
            - Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由
			- Cookie=username,zzyy  # 请求需包含cookie ,username,值zzyy(zzyy可以为正则表达式)
spring:
  cloud:
    gateway:
      routes:
        - id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
#          uri: http://localhost:8001                #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service               #匹配后提供服务的路由地址
          predicates:
            - Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由
			- Header=X-Request-Id, \d+  # 请求头要有X-Request-Id属性并且值为整数的正则表达式

Host

spring:
  cloud:
    gateway:
      routes:
        - id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
#          uri: http://localhost:8001                #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service               #匹配后提供服务的路由地址
          predicates:
            - Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由
			- Host=**.atguigu.com

post请求测试时,头文件添加Host参数:
image

Method

spring:
  cloud:
    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

Path

断言,以在前文中使用过

spring:
  cloud:
    gateway:
      routes:
        - id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
#          uri: http://localhost:8001                #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service               #匹配后提供服务的路由地址
          predicates:
            - Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由

Query

- Query=username, \d+  # 要有参数名username并且值还要是整数才能路由

RemoteAddress

 - RemoteAddr=192.168.124.1/24 # 外部访问我的IP限制,最大跨度不超过32,目前是1~24它们是 CIDR 表示法。

自定义断言

如果原有的断言不能满足我们的要求,我们可以使用自定义断言。自定义断言步骤如下:

  • 新建类名XXX需要以RoutePRedicateFactory结尾
  • 重写apply方法
  • 新建apply方法所需要的静态内部类,MyRoutePredicateFactory.Config,这个Config类就是我们的路由断言规则
  • 空参构造方法,内部调用super
  • 重写apply方法。

完整代码如下:

/** 
* 自定义断言
 * @Author:lyj
 * @Date:2024/12/30 13:32
 */
@Component
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config> {
    @Validated
    public static class Config {
        @Setter
        @Getter
        @NotNull
        private String userType;        // 钻石、金、银等用户等级
    }

    public MyRoutePredicateFactory() {
        super(MyRoutePredicateFactory.Config.class);
    }

    @Override
    public Predicate<ServerWebExchange> apply(MyRoutePredicateFactory.Config config) {
        return  new Predicate<ServerWebExchange>() {
            @Override
            public boolean test(ServerWebExchange serverWebExchange) {
                // 检查request的参数里,userType是否为指定值,符合配置则通过
                String userType = serverWebExchange.getRequest().getQueryParams().getFirst("userType");
                if (userType == null) {
                    return false;
                }
                if (userType.equals(config.getUserType())) {
                    return true;
                }
                return false;
            }
        };
    }
}

自定义配置

上述代码,缺少shortFieldOrder 方法的实现,所以不支持短格式。

spring:
  cloud:
    gateway:
      routes:
        - id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
#          uri: http://localhost:8001                #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service               #匹配后提供服务的路由地址
          predicates:
            - Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由
            - name: My
              args:
                userType: diamond

要想支持短格式,重写方法shortcutFieldOrder

@Override
public List<String> shortcutFieldOrder() {
	return Collections.singletonList("userType");
}

Fileter 过滤器

官网地址:https://docs.spring.io/spring-cloud-gateway/docs/4.0.4/reference/html/#gatewayfilter-factories

"pre"和“post”分表会在请求被执行前调用和被执行后调用,用来修改请求和响应信息。

作用:请求鉴权和异常处理、

过滤器类型包括:

  • 全局默认过滤器Global Filters
  • 单一内置过滤器GatewayFilter
  • 自定义过滤器

全局过滤器GlobalFilters

官网例子:https://docs.spring.io/spring-cloud-gateway/docs/4.0.4/reference/html/#gatewayfilter-factories。gateway出厂默认已有,直接用即可,主要用于所有的路由,不需要在配置文件中配置,只需要实现GlobalFilter接口即可。

/**
 * 自定义过滤器
 * @Author:lyj
 * @Date:2024/12/30 14:14
 */
public class MyGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public int getOrder() {
        return -1;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("【全局过滤器 MyGlobalFilter】");
        return chain.filter(exchange);
    }
}

添加自定义过滤器的配置

@Configuration
public class Myconfig {
    @Bean
    public GlobalFilter myGlobalFilter(){
        return new MyGlobalFilter();
    }
}

单一内置过滤器GatewayFilter

官网地址:https://docs.spring.io/spring-cloud-gateway/docs/4.0.4/reference/html/#gatewayfilter-factories

官网有37个过滤器.接下来,只讲常用和通用的内置过滤器:

过滤器分组 过滤器
请求头(RequestHeader)相关组 6.1 The AddRequestHeader GatewayFilter Factory
6.18The RemoveRequestHeader GatewayFilter Factory
6.29The SetRequestHeader GatewayFilter Factory
请求参数(RequestParameter)相关组 6.3The AddRequestParameter GatewayFilter Factory
6.19The RemoveRequestParameter GatewayFilter Factory
回应头(ResponseHeader)相关组 6.4The AddResponseHeader GatewayFilter Factory
6.30The SetResponseHeader GatewayFilter Factory
6.20The RemoveResponseHeader GatewayFilter Factory
前缀和路径相关组 6.14The PrefixPath GatewayFilter Factory
6.29The SetRequestHeader GatewayFilter Factory
6.16The RedirectTo GatewayFilter Factory
其他 6.37 Default Filters

测试过滤器前,被调用的微服务8001的PayGateWayController新增方法如下:

@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());
}

网关9527,设置如下:

spring:
  cloud:
    gateway:
      routes:
        - id: pay_routh3 # pay_routh3
          uri: lb://cloud-payment-service                #匹配后提供服务的路由地址
          predicates:
            - Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由

测试地址:http://localhost:9527/pay/gateway/filter

请求头(RequestHeader)相关组

he AddRequestHeader GatewayFilter Factor,指定请求头ByName

spring:
  cloud:
    gateway:
      routes:
        - id: pay_routh3 # pay_routh3
          uri: 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

spring:
  cloud:
    gateway:
      routes:
        - id: pay_routh3 # pay_routh3
          uri: lb://cloud-payment-service                #匹配后提供服务的路由地址
          predicates:
            - Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由
          filters:
			- RemoveRequestHeader=sec-fetch-site      # 删除请求头sec-fetch-site

修改前请求头值:
image

修改后,请求头sec-fetch-site被删除。

The SetRequestHeader GatewayFilter Factory,修改请求头ByName

- SetRequestHeader=sec-fetch-mode, Blue-updatebyzzyy # 将请求头sec-fetch-mode对应的值修改为Blue-updatebyzzyy

请求参数(RequestParamter)相关组

- AddRequestParameter=customerId,9527001 # 新增请求参数Parameter:k ,v
            - RemoveRequestParameter=customerName   # 删除url请求参数customerName,你传递过来也是null

回应头(ResponseHeader)相关组

- 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, http://www.atguigu.com/ # 访问路径跳转,访问http://localhost:9527/pay/gateway/filter跳转到http://www.atguigu.com/

其他

将自定义过滤,变为Global。

spring:
  cloud:
    gateway:
      default-filters:
      - AddResponseHeader=X-Response-Default-Red, Default-Blue
      - PrefixPath=/httpbin

自定义过滤器

接下来,我们将根据实际场景,看看过滤器的使用情况——统计接口的耗时情况。

此时,我们想到了3个方法:

  1. 直接在代码前后修改👎
  2. 使用AOP
  3. 通过全局过滤器搞定需求,参考:https://docs.spring.io/spring-cloud-gateway/docs/4.0.4/reference/html/#gateway-combined-global-filter-and-gatewayfilter-ordering

直接修改接口代码,代码冗余度高,代码入侵性强,在接口中加入与业务无关的代码耦合性高,可读性差,首先排除。

使用AOP,之前也有学到,这里就不详细说明了。

自定义全局过滤器

写YAML,确定路径匹配被调用端,8001

server:
  port: 9527

spring:
  application:
    name: cloud-gateway #以微服务注册进consul或nacos服务列表内
  cloud:
    consul: #配置consul地址
      host: localhost
      port: 8500
      discovery:
        prefer-ip-address: true
        service-name: ${spring.application.name}
    gateway:
      routes:
        - id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
          uri: lb://cloud-payment-service                #匹配后提供服务的路由地址
          predicates:
            - Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由
            - After=2023-12-30T23:02:39.079979400+08:00[Asia/Shanghai]

        - id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
          uri: lb://cloud-payment-service
          predicates:
            - Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由

        - id: pay_routh3 #pay_routh3
          uri: lb://cloud-payment-service                #匹配后提供服务的路由地址
          predicates:
            - Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由,默认正确地址
          filters:
            - AddRequestHeader=X-Request-atguigu1,atguiguValue1  # 请求头kv,若一头含有多参则重写一行设置

写code,引入全局过滤器

/**
 * @auther zzyy
 * @create 2023-11-22 17:27
 */
@Component
@Slf4j
public class MyGlobalFilter implements GlobalFilter, Ordered
{

    /**
     * 数字越小优先级越高
     * @return
     */
    @Override
    public int getOrder()
    {
        return 0;
    }

    private static final String BEGIN_VISIT_TIME = "begin_visit_time";//开始访问时间
    /**
     *第2版,各种统计
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public 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();
            }
        }));
    }

}

自定义单一过滤器

  • 新建类名XXX需要以GatewayFilterFactory结尾,并集成AbstractGatewayFilterFactory类。
  • 新建XXXGatewayFilterFactory.Config内部类
  • 重写apply方法
  • 重写shortcutFieldOrder
  • 空参构造方法,内部调用super
 * 自定义过滤
 * @Author:lyj
 * @Date:2024/12/31 10:09
 */
@Component
public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.Config> {
    public static class  Config {
        @Getter
        @Setter
        private String status;
    }

    public MyGatewayFilterFactory() {
        super(MyGatewayFilterFactory.Config.class);
    }

    @Override
    public GatewayFilter apply(MyGatewayFilterFactory.Config config) {
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                ServerHttpRequest request =  exchange.getRequest();
                System.out.println("进入自定义网关过滤器MyGatewayFilterFactory,status===="+config.getStatus());
                if(request.getQueryParams().containsKey("atguigu")) {
                    return chain.filter(exchange);
                }else {
                    exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);
                    return exchange.getResponse().setComplete();
                }
            }
        };
    }

    @Override
    public List<String> shortcutFieldOrder() {
        List<String> list = new ArrayList<String>();
        list.add("status");
        return list;
    }
}

自定义构造参数在spring.cloud.gateway.routes.-id.filters下,名称为自定义过滤器XXXGatewayFilterFactory前的XXX。

posted @ 2024-12-31 10:32  陆陆无为而治者  阅读(14)  评论(0编辑  收藏  举报