Spring Cloud Gateway网关的高级特性之GatewayFilter Factories(路由过滤器)

1、GatewayFilter Factories(路由过滤器)

官方访问地址:点击这里

来自官方的解释如下图所示:
在这里插入图片描述

简单来说就是:

  • 客户端向 Spring Cloud Gateway 发送请求。
  • 如果请求与某个路由匹配,则该请求会被传递给 Gateway Web Handler。
  • Gateway Web Handler 将请求通过一系列过滤器,这些过滤器可以做一些预处理工作(比如添加头部信息、修改请求参数等)。
  • 过滤器处理完成后,实际的代理请求才会被发送到目标服务。
  • 当响应从目标服务返回时,它还会经过相同的过滤器链,这时过滤器可以做一些后处理工作(例如修改响应内容、添加响应头等)。
  • 最终处理完毕后,响应被返回给客户端。

路由过滤器的主要作用就是用来做请求鉴权、异常处理等,比较典型的就有记录接口调用时长统计。

2、 Filter过滤的类型

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

3、 Gateway内置的过滤器

这里只演示常用的内置过滤器,其他的原理都是一样的。

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

我们在网关controller中编写测试接口:
Example 14. GateWayController.java

@RestController
public class GateWayController{
    @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-red")
                    || headName.equalsIgnoreCase("X-Request-my"))  {
                result = result+headName + "\t " + headValue +" ";
            }
        }
        return ResultData.success("getGatewayFilter 过滤器 test: "+result+" \t "+ DateUtil.now());
    }
}

Example 14. application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: add_request_header_route
        uri: https://example.org
        filters:
        - AddRequestHeader=X-Request-red, blue # 请求头kv,若一头含有多参则重写一行设置
        - AddRequestHeader=X-Request-my,name

重启服务,并访问http://localhost:端口号/pay/gateway/filter,查看控制台信息。

3.2 The RemoveRequestHeader GatewayFilter Factory (删除请求头ByName)

spring:
  cloud:
    gateway:
      routes:
      - id: removerequestheader_route
        uri: https://example.org
        filters:
        - RemoveRequestHeader=sec-fetch-site	# 删除请求头sec-fetch-site

注意:观察删除前后控制台打印的信息
删除前:
在这里插入图片描述
删除后:
在这里插入图片描述

3.3 The SetPath GatewayFilter Factory(修改请求头)

spring:
  cloud:
    gateway:
      routes:
      - id: setpath_route
        uri: https://example.org
        predicates:
        - Path=/red/{segment}
        filters:
        - SetRequestHeader=sec-fetch-mode,Blue-updatebyzzyy # 将请求头sec-fetch-mode对应的值修改为Blue-updatebyzzyy

修改前:
在这里插入图片描述

修改后(注意要重启服务):
在这里插入图片描述

3.4 The AddRequestParameter\RemoveRequestParameter GatewayFilter Factory(添加\删除请求参数)

spring:
  cloud:
    gateway:
      routes:
      - id: removerequestparameter_route
        uri: https://example.org
        filters:
        - RemoveRequestParameter=customerName # 删除url请求参数customerName,你传递过来也是null
        - AddRequestParameter=customerId,9527001 # 新增请求参数Parameter:k ,v

修改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-red")
                    || headName.equalsIgnoreCase("X-Request-my"))  {
                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());
}
访问地址:
http://localhost:端口号/pay/gateway/filter 
http://localhost:端口号/pay/gateway/filter?customerld=9999&customerName=z3 

注意观察控制台打印信息。。

3.5 响应头相关的配置

  1. The AddResponseHeader GatewayFilter Factory
  2. The RemoveResponseHeader GatewayFilter Factory
  3. ** The SetRequestHeader GatewayFilter Factory**
spring:
  cloud:
    gateway:
      routes:
      - id: add_response_header_route
        uri: https://example.org
        filters:
        - AddResponseHeader=X-Response-Red, Blue #新增响应头参数,并将X-Response-Red的值设置为Blue
        - RemoveResponseHeader=Content-Type # 将默认自带Content-Type回应属性删除
        - SetResponseHeader=Date,2099-11-11 # 设置响应头Date值为2099-11-11

3.6 前缀和路径相关的配置

  1. The PrefixPath GatewayFilter Factory(自动添加路径前缀)
  2. The SetPath GatewayFilter Factory(修改访问路径)
  3. The RedirectTo GatewayFilter Factory(重定向到某个页面)
spring:
  cloud:
    gateway:
      routes:
      - id: prefixpath_route
        uri: https://example.org
      # - Path=/gateway/filter/** # 真实地址
      - Path=/gateway/filter/** # 断言,为配合PrefixPath测试过滤
      - Path=/XYZ/abc/{segment}  # 断言,为配合SetPath测试,{segment}的内容最后被SetPath取代
        filters:
        - PrefixPath=/mypath	# 表示加了这个前缀胡访问的就是http://localhost:端口号/mypath/gateway/filter,,但是实际上调用的还是http://localhost:端口号/gateway/filter
        - SetPath=/pay/gateway/{segment}  # {segment}表示占位符,你写abc也行但要上下一致
        - RedirectTo=302, http://www.baidu.com/ # 访问http://localhost:9527/gateway/filter跳转到http://www.baidu.com/

4、自定义全局Filter

需求:统计接口调用耗时情况。
通过自定义全局过滤器搞定上述需求。

自定义全局过滤器的官方地址点击这里查看

4.1 实现步骤

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

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

2、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=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,若一头含有多参则重写一行设置

3、测试
浏览器访问:

  • http://localhost:9527/pay/gateway/info
  • http://localhost:9527/pay/gateway/get/1
  • http://localhost:9527/pay/gateway/filter
    http://localhost:9527/pay/gateway/info
    请注意,上述示例代码仅供参考,你可能需要根据你的项目需求和实际情况进行适当的调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

-今非昔比°

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值