springboot集成Gateway「过滤器」

256 阅读3分钟

GatewayFilter是网关中提供的过滤器,对请求进行各种处理,然后响应给客户端。

一、过滤器知识点

1. 生命周期

Spring Cloud Gateway 的 Filter 生命周期很简单,它只有:pre 和 post 。

  • PRE: 这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
  • POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的 HTTPHeader、收集统计信息和指标、将响应从微服务发送给客户端等。

2. 过滤器类型

Spring Cloud Gateway 的 Filter 从作用范围上课分为两种:GatewayFilter 和 GlobalFilter。

局部过滤器(GatewayFilter)

局部过滤器(GatewayFilter)是针对单个路由的过滤器,对访问的URL过滤,切面处理。在Spring Cloud Gateway中通过GatewayFilter的形式内置了很多不同类型的局部过滤器。

全局过滤器(GlobalFilter)

全局过滤器(GlobalFilter)作用于所有的路由,可以通过自定义实现自己的 GlobalFilter。通过全局过滤器实现对所有请求的的统一校验。

二、实战

以上篇 springboot集成Gateway & Nacos「再来一刀」 搭建的测试环境开发。

1. 局部过滤

局部过滤含有26个GatewayFilter Factory,下面用 AddRequestHeader 和 AddResponseHeader 举栗子。

AddRequestHeader :通过配置name和value可以增加请求的header。 AddResponseHeader:通过配置name和value可以增加请求的参数。

其它的 Factory 的使用,可以参考其它作者的文章

二当家的黑板报:spring cloud gateway系列教程2——GatewayFilter_上篇

(1)application.yml 配置

spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
          lower-case-service-id: true
      routes:
        - id: springboot-gateway-client-a
          uri: lb://springboot-gateway-client-a
          predicates:
            - Path=/sgca/**
          filters:
            - AddRequestHeader=X-Request-Token, 2020ABC
            - AddResponseHeader=X-Response-Token, 2020ABC

(2)测试接口

@RequestMapping(value = "/2")
    public String test2(@RequestHeader(value = "X-Request-Token", required = false) String token){
        return "req token:"+token;
    }

2. 全局过滤

自定义全局过滤器是平时开发中最常用的,用于对所有请求的安全校验。

实现拦截器,需要继承两个类:GlobalFilter, Ordered。

GlobalFilter:全局过滤拦截器。 Orderer:拦截器的顺序,数值越小,执行的优先级越高。

(1)提取Request内容

        ServerHttpRequest request = exchange.getRequest();
        String path = request.getPath().pathWithinApplication().value();
        String scheme = request.getURI().getScheme();
        HttpMethod method = request.getMethod();
        HttpHeaders httpHeaders = request.getHeaders();
        InetSocketAddress remoteAddress = request.getRemoteAddress();
        //不建议提取body数据,因为请求体数据只能被消费一次。
        logger.info("\npath:{}\nscheme:{}\nmethod:{}\nheaders:{}\nremoteAddress:{}",
                path,scheme,method,httpHeaders,remoteAddress);

(2)header增加token

        ServerHttpRequest newRequest = exchange.getRequest().mutate().headers(headers -> {
            headers.add("X-Gatewaw-Token","2022ABC");
            headers.add("X-Gatewaw-Token","2022ABC");
        }).build();

(3)计算请求时长

        exchange.getAttributes().put("START_TIME", System.currentTimeMillis());

        return chain.filter(exchange.mutate().request(newRequest).build()).then( Mono.fromRunnable(() -> {
            Long startTime = exchange.getAttribute("START_TIME");
            if (startTime != null) {
                Long executeTime = (System.currentTimeMillis() - startTime);
                logger.info(exchange.getRequest().getURI().getRawPath() + " : " + executeTime + "ms");
            }
        }));

三、开发避免的坑

平时开发过程是,尽量避免提取request body数据,因为请求体数据只能被消费一次。

解决方案:SpringCloud Gateway 内部提供了一个断言工厂类ReadBodyPredicateFactory,这个类实现了读取Request的Body内容并放入缓存,我们可以通过从缓存中获取body内容来实现我们的目的。

具体的如何使用,还没尝试,后续更新吧。

springboot集成Gateway DEMO:gitee.com/renxiaoshi/…