GateWay的高级特性

时间:2024-7-11    作者:老大夫    分类: SpringCloud


三大部分:路由(有没有的问题)、断言(可不可以访问的问题)、过滤(访问前后进行的操作)

1. 路由动态映射

由于存在geteway映射写死的问题

解决办法:

改写成 lb://service (服务名称)lb是loadbalence负载均衡的意思

2. Predicate断言

两种配置方法:简介配置、全面配置

 #id:我们自定义的路由 ID,保持唯一
  ##uri:目标服务地址
  ##predicates:路由条件,Predicate接受一个输入参数返回一个布尔值。
  ##            该属性包含多种默认方法来将Predicate组合成其他复杂的逻辑(比如:与,或,非)
  1. 配置01 时间点设置
  • 获得时间戳
public void test01(){
        ZonedDateTime zbj = ZonedDateTime.now(); // 默认时区
        System.out.println(zbj);
    }

得到 2024-07-11T14:54:11.992550800+08:00[Asia/Shanghai]

  • 配置predicate断言

After:超过时间戳后的时间才能访问
Before:在时间戳之前才能访问
Between:时间戳1,时间戳2 在时间戳之间才能访问

    gateway:
      routes:
        - id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
          uri: lb://cloud-payment-service          #匹配后提供服务的路由地址
          predicates:
            - Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由
            - After=2024-07-11T15:00:11.992550800+08:00[Asia/Shanghai]
  1. 配置02 cookie设置
  • 配置predicate断言

,前面是cookie名称,后面是正则表达式

- Cookie=username,zzyy
  1. 配置03 Header请求头设置
  • 配置predicate断言
- Header=X-Request-Id, \d+  # 请求头要有X-Request-Id属性并且值为整数的正则表达式
  1. 配置04 Host设置
  • 配置predicate断言

Host在请求头中 =后面是正则表达式

- Host=**.atguigu.com
  1. 配置05 请求参数断言设置
  • 配置predicate断言

=后是参数名,后是正则表达式

- Query=username, \d+  # 要有参数名username并且值还要是整数才能路由
  1. 配置06 远程地址断言设置

限制外部访问的ip地址限制

  • 配置predicate断言
- RemoteAddr=192.168.124.1/24 # 外部访问我的IP限制,最大跨度不超过32,目前是1~24它们是 CIDR 表示法。
  1. 配置07 访问方式设置
- Method:Post

3. 自定义Predicate断言

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

  1. 创建一个类继承RoutePredicateFactory
package com.atguigu.cloud.mygateway;

import org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory;

public class MyRoutePredicateFactory extends RoutePredicateFactory {
}
  1. 重写applay方法
package com.atguigu.cloud.mygateway;

import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory;
import org.springframework.web.server.ServerWebExchange;

import java.util.function.Predicate;

public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<AbstractRoutePredicateFactory.Config> {

    @Override
    public Predicate<ServerWebExchange> apply(MyRoutePredicateFactory.Config config) {
        return null;
    }
}
  1. 新建apply方法所需要的静态内部类MyRoutePredicateFactory.Config,这个Config类就是我们的路由断言规则,重要
package com.atguigu.cloud.mygateway;

import jakarta.validation.constraints.NotEmpty;
import lombok.Getter;
import lombok.Setter;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;

import java.util.function.Predicate;

/**
 * 需求:会员按照金银铜铁分类,控制不同等级是否可以访问
 */
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config> {

    //这个Config就是断言规则
    @Validated
    public static class Config{
        @Setter
        @Getter
        @NotEmpty
        private String userType;//会员的金银铜铁等级

    }

    @Override
    public Predicate<ServerWebExchange> apply(MyRoutePredicateFactory.Config config) {
        return null;
    }
}
  1. 空参构造方法内部调用super
package com.atguigu.cloud.mygateway;

import jakarta.validation.constraints.NotEmpty;
import lombok.Getter;
import lombok.Setter;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;

import java.util.function.Predicate;

/**
 * 需求:会员按照金银铜铁分类,控制不同等级是否可以访问
 */
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config> {

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

    //这个Config就是断言规则
    @Validated
    public static class Config{
        @Setter
        @Getter
        @NotEmpty
        private String userType;//会员的金银铜铁等级

    }

    @Override
    public Predicate<ServerWebExchange> apply(MyRoutePredicateFactory.Config config) {
        return null;
    }
}
  1. 重写apply方法
package com.atguigu.cloud.mygateway;

import jakarta.validation.constraints.NotEmpty;
import lombok.Getter;
import lombok.Setter;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;

import java.util.function.Predicate;

/**
 * 需求:会员按照金银铜铁分类,控制不同等级是否可以访问
 */
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config> {

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

    //这个Config就是断言规则
    @Validated
    public static class Config{
        @Setter
        @Getter
        @NotEmpty
        private String userType;//会员的金银铜铁等级

    }

    @Override
    public Predicate<ServerWebExchange> apply(MyRoutePredicateFactory.Config config) {
        return new Predicate<ServerWebExchange>() {
            @Override
            public boolean test(ServerWebExchange serverWebExchange) {
                //检查request里的参数,usertype是否为指定的值,符合就通过
                //localhost:9527/pay/gateway/get/1?usertype=diamond
                String userType = serverWebExchange.getRequest().getQueryParams().getFirst("userType");
                if (userType==null || userType.isEmpty()){
                    return false;
                }
                //如果参数存在就和config参数进行比较
                if(userType.equalsIgnoreCase(config.getUserType())){
                    return true;
                }
                return false;
            }
        };
    }
}
  1. 设置yml文件的断言
- My=diamond

使用快捷设置方法,发现报错:Failed to bind properties under '' to com.atguigu.cloud.mygateway.MyRoutePredicateFactory$Config
绑定报错

- name: My
args:
userType: diamond

使用全参数配置,发现恢复正常

原因:自定义断言类中没有重写快捷设置方法 shortcutFieldOrder

  1. 重写shortcutFieldOrder实现快捷设定
package com.atguigu.cloud.mygateway;

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;

/**
 * 需求:会员按照金银铜铁分类,控制不同等级是否可以访问
 */
@Component
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config> {

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

    //这个Config就是断言规则
    @Validated
    public static class Config{
        @Setter
        @Getter
        @NotEmpty
        private String userType;//会员的金银铜铁等级

    }

    @Override
    public Predicate<ServerWebExchange> apply(MyRoutePredicateFactory.Config config) {
        return new Predicate<ServerWebExchange>() {
            @Override
            public boolean test(ServerWebExchange serverWebExchange) {
                //检查request里的参数,usertype是否为指定的值,符合就通过
                //localhost:9527/pay/gateway/get/1?usertype=diamond
                String userType = serverWebExchange.getRequest().getQueryParams().getFirst("userType");
                if (userType==null || userType.isEmpty()){
                    return false;
                }
                //如果参数存在就和config参数进行比较
                if(userType.equalsIgnoreCase(config.getUserType())){
                    return true;
                }
                return false;
            }
        };
    }

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

4. 过滤器Filter

  • GlobalFilter全局过滤器 默认出厂自带的不用更改
  • GateWayFilter单一内置过滤器(网关过滤器),作用在单一路由或者某个路由分组
  • 自定义过滤器

GateWay内置过滤器

请求头(RequestHeader)相关组过滤器

The AddRequestHeader GatewayFilter Factory

添加请求头内容

  • 8001新增controller用于测试
@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());
    }
  • 9527GateWay网关yml新增加过滤内容
 - 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

移除指定的请求头

  • 9527的yml设置
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: http://localhost:8001                #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service                #匹配后提供服务的路由地址
          predicates:
            - Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由
            - After=2023-12-30T23:02:39.079979400+08:00[Asia/Shanghai]
            #- Cookie=username,zzyy
            # - Header=X-Request-Id, \d+ # 请求头要有X-Request-Id属性并且值为整数的正则表达式
            #- Host=**.atguigu.com
            #- Query=username, \d+  # 要有参数名username并且值还要是整数才能路由
            #- RemoteAddr=192.168.124.1/24 # 外部访问我的IP限制,最大跨度不超过32,目前是1~24它们是 CIDR 表示法。
            - My=gold
#            - name: My
#              args:
#                userType: diamond

        - 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
          uri: 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

设置请求头内容

  • 修改9527GateWay网关yml
- SetRequestHeader=sec-fetch-mode, Blue-updatebyzzyy # 将请求头sec-fetch-mode对应的值修改为Blue-updatebyzzyy

请求参数(RequestParameter)相关组过滤器

The AddRequestParameter GatewayFilter Factory

The RemoveRequestParameter GatewayFilter Factory

添加请求参数
删除请求参数

  • 修改8001的controller增加parameter的测试内容
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 io.swagger.v3.oas.annotations.Operation;
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;
import java.util.concurrent.TimeUnit;

/**
 * @auther zzyy
 * @create 2023-11-20 13:09
 */
@RestController
public class PayGateWayController
{
    @Resource
    PayService 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());
    }
}
  • 修改yml
            - AddRequestParameter=customerId,9527001 # 新增请求参数Parameter:k ,v
            - RemoveRequestParameter=customerName   # 删除url请求参数customerName,你传递过来也是null

回应头(ResponseHeader)相关组过滤器

The AddResponseHeader GatewayFilter Factory

- AddResponseHeader=X-Response-atguigu, BlueResponse # 新增请求参数X-Response-atguigu并设值为BlueResponse

The SetResponseHeader GatewayFilter Factory

- SetResponseHeader=Date,2099-11-11 # 设置回应头Date值为2099-11-11

The RemoveResponseHeader GatewayFilter Factory

- RemoveResponseHeader=Content-Type # 将默认自带Content-Type回应属性删除

前缀和路径相关组过滤器

The PrefixPath GatewayFilter Factory添加路径

在路径前加上 /pay
访问的时候不用在地址栏输入/pay了,实际访问的是带/pay的地址

 - PrefixPath=/pay # http://localhost:9527/pay/gateway/filter

The SetPath GatewayFilter Factory修改路径

设置路径
占位符{}内用什么字母都可以,

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: http://localhost:8001                #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service          #匹配后提供服务的路由地址
          predicates:
            - Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由
            #- After=2023-11-20T17:38:13.586918800+08:00[Asia/Shanghai]
            - Before=2023-12-29T17:58:13.586918800+08:00[Asia/Shanghai]
            #- Between=2023-11-21T17:38:13.586918800+08:00[Asia/Shanghai],2023-11-22T17:38:13.586918800+08:00[Asia/Shanghai]
            #- Cookie=username,zzyy
            #- Header=X-Request-Id, \d+  # 请求头要有X-Request-Id属性并且值为整数的正则表达式
            #- Host=**.atguigu.com
            #- Query=username, \d+  # 要有参数名username并且值还要是整数才能路由
            #- RemoteAddr=192.168.1.196/24 # 外部访问我的IP限制,最大跨度不超过32,目前是1~24。

        - 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
          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-updatebyzzyy # 将请求头sec-fetch-mode对应的值修改为Blue-updatebyzzyy
            #- AddRequestParameter=customerId,9527001 # 新增请求参数Parameter:k ,v
            #- RemoveRequestParameter=customerName   # 删除url请求参数customerName,你传递过来也是null
            #- 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也行但要上下一致

/XYZ/abc/{segment},{segment}就是个占位符,等价于SetPath后面指定的{segment}内容

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

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

The RedirectTo GatewayFilter Factory请求转发和重定向

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: http://localhost:8001                #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service          #匹配后提供服务的路由地址
          predicates:
            - Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由
            #- After=2023-11-20T17:38:13.586918800+08:00[Asia/Shanghai]
            - Before=2023-12-29T17:58:13.586918800+08:00[Asia/Shanghai]
            #- Between=2023-11-21T17:38:13.586918800+08:00[Asia/Shanghai],2023-11-22T17:38:13.586918800+08:00[Asia/Shanghai]
            #- Cookie=username,zzyy
            #- Header=X-Request-Id, \d+  # 请求头要有X-Request-Id属性并且值为整数的正则表达式
            #- Host=**.atguigu.com
            #- Query=username, \d+  # 要有参数名username并且值还要是整数才能路由
            #- RemoteAddr=192.168.1.196/24 # 外部访问我的IP限制,最大跨度不超过32,目前是1~24。

        - 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
          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-updatebyzzyy # 将请求头sec-fetch-mode对应的值修改为Blue-updatebyzzyy
            #- AddRequestParameter=customerId,9527001 # 新增请求参数Parameter:k ,v
            #- RemoveRequestParameter=customerName   # 删除url请求参数customerName,你传递过来也是null
            #- 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
            - RedirectTo=302, http://www.atguigu.com/ # 访问http://localhost:9527/pay/gateway/filter跳转到http://www.atguigu.com/

其他过滤器

Default Filters会应用到所有路由上,不推荐

自定义过滤器

  1. 新建MyGlobalFilter
package com.atguigu.cloud.mygateway;

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;

import java.util.Map;

/**
 * @auther zzyy
 * @create 2023-11-22 17:41
 */

@Component //不要忘记
@Slf4j
public class MyGlobalFilter implements GlobalFilter, Ordered
{
    public static final String BEGIN_VISIT_TIME="begin_visit_time";//开始调用方法的时间
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
    {
        //1.先记录下访问接口的开始时间
        exchange.getAttributes().put(BEGIN_VISIT_TIME,System.currentTimeMillis());
        //返回统计的各个结果给后台
        return chain.filter(exchange).then(Mono.fromRunnable(()->{
            Long beginVisitTime = (Long) exchange.getAttribute(BEGIN_VISIT_TIME);
            if (beginVisitTime!=null){
                log.info("访问接口主机:"+exchange.getRequest().getURI().getHost());
                log.info("访问接口URL:"+exchange.getRequest().getURI().getPath());
                log.info("访问接口URL后面的参数:"+exchange.getRequest().getURI().getRawQuery());
                log.info("访问接口主机:"+exchange.getRequest().getURI().getHost());
                log.info("访问接口时长:"+(System.currentTimeMillis()-beginVisitTime)+"毫秒");
                log.info("===============分割线======================");
                System.out.println();

            }
        }));
    }

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

yml里路由断言设置好了哪些链接路由归GateWay管(之前的设置不用动)
然后运行就可以了

自定义单一内置过滤器

  1. 新建类名XXX需要以GatewayFilterFactory结尾,并继承AbstractGatewayFilterFactory类
package com.atguigu.cloud.mygateway;

import lombok.Getter;
import lombok.Setter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.stereotype.Component;

@Component
public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.Config>
{
    public static class Config {
        @Setter
        @Getter
        private String status;
    }
}
  1. 重写apply方法
package com.atguigu.cloud.mygateway;

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;

/**
 * @auther zzyy
 * @create 2023-04-29 17:37
 */
@Component
public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.Config>
{
    @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();
                }
            }
        };
    }

    public static class Config {
        @Setter @Getter
        private String status;
    }
}
  1. 重写shortcutFieldOrder快捷设置方法
package com.atguigu.cloud.mygateway;

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.Arrays;
import java.util.List;

@Component
public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.Config>
{
    @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();
                }
            }
        };
    }

    public static class Config {
        @Setter
        @Getter
        private String status;//设定一个状态值,它等于多少才可以访问
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("status");
    }
}
  1. 重写空参构造方法
package com.atguigu.cloud.mygateway;

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.Arrays;
import java.util.List;

@Component
public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.Config>
{

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

    public static class Config {
        @Setter
        @Getter
        private String status;//设定一个状态值,它等于多少才可以访问
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("status");
    }
}
  1. 配置yml
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=2024-07-11T15:00:11.992550800+08:00[Asia/Shanghai]
#            - Cookie=username,zzyy
#            - Header=X-Request-Id, \d+  # 请求头要有X-Request-Id属性并且值为整数的正则表达式
#            - Host=**.atguigu.com
#            - Query=username, \d+  # 要有参数名username并且值还要是整数才能路由
#            - name: My
#              args:
#                userType: diamond
#            - My=diamond
#            - RemoteAddr=10.0.0.1/24 # 外部访问我的IP限制,最大跨度不超过32,目前是1~24它们是 CIDR 表示法。

        - 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/**              # 断言,路径相匹配的进行路由,默认正确地址
#            - Path=/gateway/filter/**              # 断言,路径相匹配的进行路由,默认正确地址
#            - Path=/XYZ/abc/{segment}           # 断言,为配合SetPath测试,{segment}的内容最后被SetPath取代
          filters:
            - My=atguigu
#            - AddRequestHeader=X-Request-atguigu1,atguiguValue1  # 请求头kv,若一头含有多参则重写一行设置
#            - AddRequestHeader=X-Request-atguigu2,atguiguValue2
#            - RemoveRequestHeader=sec-fetch-site      # 删除请求头sec-fetch-site
#            - SetRequestHeader=sec-fetch-mode, Blue-updatebyzzyy # 将请求头sec-fetch-mode对应的值修改为Blue-updatebyzzyy
#            - AddRequestParameter=customerId,9527001 # 新增请求参数Parameter:k ,v
#            - RemoveRequestParameter=customerName   # 删除url请求参数customerName,你传递过来也是null
#            - 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/


扫描二维码,在手机上阅读

推荐阅读: