Spring-Cloud-Gateway实现自定义过滤器

Spring-Cloud-Gateway实现自定义过滤器


本篇博客主要搬运自开课吧提供的课堂笔记,目的是方便自身复习查找,如有不当之处,请联系博主

过滤器执行次序

Spring-Cloud-Gateway 基于过滤器实现,同 zuul 类似,有pre和post两种方式的 filter,分别处理前置逻辑和后置逻辑。客户端的请求先经过pre类型的 filter,然后将请求转发到具体的业务服务,收到业务服务的响应之后,再经过post类型的 filter 处理,最后返回响应到客户端。
过滤器执行流程如下,order 越大,优先级越低,如图所示。
在这里插入图片描述
过滤器分为全局过滤器和局部过滤器。

  • 全局过滤器:对所有路由生效
  • 局部过滤器:对指定的路由生效

全局过滤器

实现 GlobalFilter 和 Ordered,重写相关方法,加入到spring容器管理即可,无需配置,全局过滤器对所有的路由都有效。代码如下。

@Configuration
public class FilterConfig
{

    @Bean
    public GlobalFilter a()
    {
        return new AFilter();
    }

    @Bean
    public GlobalFilter b()
    {
        return new BFilter();
    }

    @Bean
    public GlobalFilter c()
    {
        return new CFilter();
    }

    @Bean
    public GlobalFilter myAuthFilter()
    {
        return new MyAuthFilter();
    }


    @Slf4j
    static class AFilter implements GlobalFilter, Ordered
    {

        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
        {
            log.info("AFilter前置逻辑");
            return chain.filter(exchange).then(Mono.fromRunnable(() ->
            {
                log.info("AFilter后置逻辑");
            }));
        }

        //   值越小,优先级越高
        @Override
        public int getOrder()
        {
            return HIGHEST_PRECEDENCE + 100;
        }
    }

    @Slf4j
    static class BFilter implements GlobalFilter, Ordered
    {
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
        {
            log.info("BFilter前置逻辑");
            return chain.filter(exchange).then(Mono.fromRunnable(() ->
            {
                log.info("BFilter后置逻辑");
            }));
        }

        @Override
        public int getOrder()
        {
            return HIGHEST_PRECEDENCE + 200;
        }
    }

    @Slf4j
    static class CFilter implements GlobalFilter, Ordered
    {

        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
        {
            log.info("CFilter前置逻辑");
            return chain.filter(exchange).then(Mono.fromRunnable(() ->
            {
                log.info("CFilter后置逻辑");
            }));
        }

        @Override
        public int getOrder()
        {
            return HIGHEST_PRECEDENCE + 300;
        }
    }


    @Slf4j
    static class MyAuthFilter implements GlobalFilter, Ordered {

        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            log.info("MyAuthFilter权限过滤器");
            String token = exchange.getRequest().getHeaders().getFirst("token");
            if (StringUtils.isBlank(token)) {
                exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                return exchange.getResponse().setComplete();
            }

            return chain.filter(exchange);
        }

        @Override
        public int getOrder() {
            return HIGHEST_PRECEDENCE + 400;
        }
    }


}

配置文件如下:

  cloud:
    gateway:
      routes:
        - id: url-proxy-2
          uri: lb://cloud-payment-service
          predicates:
            - Path=/payment/**

定义了4个全局过滤器,顺序为A>B>C>MyAuthFilter,其中全局过滤器MyAuthFilter中判断令牌是否存在,如果令牌不存在,则返回401状态码,表示没有权限访问,使用Postman执行请求,如图所示。
在这里插入图片描述
如果码掉过滤器MyAuthFilter,则可以在控制台中看出order大小对过滤器执行顺序的影响。
在这里插入图片描述

局部过滤器

定义局部过滤器步骤如下。

  • 需要实现GatewayFilter, Ordered,实现相关的方法
  • 包装GatewayFilter,产生GatewayFilterFactory
  • GatewayFilterFactory加入到过滤器工厂,并且注册到spring容器中。
  • 在配置文件中进行配置,如果不配置则不启用此过滤器规则。

接下来定义局部过滤器,对于请求头user-id校验,如果不存在user-id请求头,直接返回状态码406。代码如下。

@Component
public class UserIdCheckGatewayFilterFactory extends AbstractGatewayFilterFactory<Object>
{
    @Override
    public GatewayFilter apply(Object config)
    {
        return new UserIdCheckGateWayFilter();
    }

    @Slf4j
    static class UserIdCheckGateWayFilter implements GatewayFilter, Ordered
    {
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
        {
            String url = exchange.getRequest().getPath().pathWithinApplication().value();
            log.info("请求URL:" + url);
            log.info("method:" + exchange.getRequest().getMethod());
            //获取header
            String userId = exchange.getRequest().getHeaders().getFirst("user-id");
            log.info("userId:" + userId);

            if (StringUtils.isBlank(userId))
            {
                log.info("*****头部验证不通过,请在头部输入  user-id");
                //终止请求,直接回应
                exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
                return exchange.getResponse().setComplete();
            }
            return chain.filter(exchange);
        }

        //   值越小,优先级越高
        @Override
        public int getOrder()
        {
            return HIGHEST_PRECEDENCE;
        }
    }


}

配置文件application.yml代码如下。

spring:
  cloud:
    gateway:
      routes:        
        - id: service14
          uri: http://127.0.0.1:9001
          predicates:
            - Path=/{segment}
      default-filters:
        - PrefixPath=/payment
        - UserIdCheck
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值