欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

spring webflux过滤器

程序员文章站 2022-07-03 22:25:52
...

    spring5 webflux模块中的webfilter模型与其他过滤器或拦截器是类似的,众多filter可以组成过滤链,过滤器链的图示就不画了。

    webflux filter目前没有servlet filter中的url pattern功能,它对所有请求进行过滤,如果要实现url pattern可以自己在过滤器中匹配url。

 

过滤器的调用顺序

    如果有多个webflux webfliter,那其调用的先后顺序如何确定?在过滤链中的调用顺序遵循如下规则:

     1.webfilter实现类上有@Order注解的排在没有该注解的前面.

     2. 对有@Order注解的webfliter,order值(为有符号的int)小的排在前面。

     3. 对没有@Order注解的,按实现类的全限定类名(含有包名)的字典序升序排列。

     4. 过滤器也是spring bean,绝大多数情况下是单例,如果不是单例,这些实例之间

     调用顺序估计按照实例化的时间先后排列。

   

 

  webfliter实现

  webflux中的filter要实现org.springframework.web.server.WebFilter接口,该接口只有一个方法filter。

 

  两个过滤器实现:RequestFilter1和RequestFilter2.

 

  @Component

  @Order(-5)

  public  class RequestFilter1 implements WebFilter {

          @Override

          //返回Mono<Void> 表示该过滤器的处理已经结束。

         public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain)           {

             /*ServerWebExchange寓意交换/兑换(exchange):用请求换回响应. 所以ServerWebExchange包含有成对的http请求对象ServerHttpRequest和http响应对象ServerHttpResponse.

            ServerHttpRequest是webflux controller中的http请求对象,类似webmvc中的HttpServletRequest

           */

            ServerHttpRequest request =  exchange.getRequest();

            ServerHttpResponse response =  exchange.getResponse(); 

 

           //获取请求http头appKey值

           String appKey = request.getHeaders().getFirst("appKey");

           System.out.println("appKey="+appKey);

 

           //添加请求属性key和value

          exchange.getAttributes().put("k1", "v1");

           

           /*过滤器链的概念都是类似的,调用过滤器链的filter方法将请求转到下一个filter,如果该filter是最后一  个filter,那就转到

           该请求对应的handler,也就是controller方法或函数式endpoint */

           return chain.filter(exchange);

        }

    }

}

 

 @Component

 //@Order(1)

 public  class RequestFilter2 implements WebFilter {

    

    @Override

    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {

           ServerHttpRequest request =  exchange.getRequest();

           // 获取上个filter设置的属性k1

           String value = (String)exchange.getAttributes().get("k1");

           System.out.println("value="+value);

           return chain.filter(exchange);

        }

    }

}

 

过滤器的通常用法  

 过滤器通常用来实现一些横切的逻辑,例如认证授权、日志记录。

下面的过滤器检查http请求头中是否有token头,如果没有则将请求forward转到/auth/error,由对应的controller进行处理。这个也演示了如何用WebFilter来forward请求。

@Component

public  class AuthFilter implements WebFilter {

   

    @Override

    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {

           ServerHttpRequest request =  exchange.getRequest();

           //ServerHttpResponse response =  exchange.getResponse(); 

 

           String tokenValue = request.getHeaders().getFirst("token");

           if(null == token){

                /*http头中没有appKey,修改请求的目标url为/auth/error

                  request.mutate返回一个请求构建器(builder design pattern),path方法修改请求的url,build方法返回新的request 

                  最后调用chain.filter将请求forward到修改后的url:/auth/error

               */ 

               ServerHttpRequest authErrorReq = request.mutate().path("/auth/error").build();

               //erverWebExchange.mutate类似,构建一个新的ServerWebExchange

               ServerWebExchange authErrorExchange =                 exchange.mutate().request(authErrorReq).build();

               return chain.filter(autherrorExchange);

           }

           else{

               return chain.filter(exchange);

           }

        }

    }

 

}

 

 

 

也可在过滤器中直接处理请求,跳过后面的filter和controller

@Component

public  class AuthFilter implements WebFilter {

    @Override

    public Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) {

           ServerHttpRequest request =  serverWebExchange.getRequest();

           ServerHttpResponse response =  serverWebExchange.getResponse(); 

 

           String tokenValue = request.getHeaders().getFirst("token");

           if(null == token){

                   // 直接返回响应结果,跳过后面的filter和controller

                   response.setStatusCode(HttpStatus.OK);

                   response.getHeaders().setContentType(MediaType.APPLICATION_JSON);

                   return response.writeWith(Mono.just(response.bufferFactory().wrap("{\"msg\":\"no token\"}".getBytes())));

            }

            else {

                return webFilterChain.filter(serverWebExchange);

            }

        }

    }

 

}

 

 

过滤器后处理

前面的演示都还是前处理,在后面的filter完成之后,控制流回到本filter。

可以在WebFilterChain的filter方法后面加入后处理逻辑,这个要熟悉spring reactor3的运算符/算子(operator), 例如doFinally、then、thenEmpty、thenMany、map、flatMap等,后处理逻辑分布在这些运算符中,只要最终返回Mono<Void>即可。

 

@Component

public  class PostProcessingFilter implements WebFilter {

    @Override

    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {

        //后处理,打印完成信号的值

        return chain.filter(exchange).doFinally(s ->  System.out.println("signal="+s.toString()));

        

        /* 其他几种

        * or 1: 建议尽量采用链式的fluent连贯写法

        *   Mono<Void>  completeMono = chain.filter(exchange);

        *   return completeMono.doFinally(s -> System.out.println("signal="+s.toString()));

        */

        //or 2: return chain.filter(exchange).thenEmpty(other);

        //or 3: return chain.filter(exchange).thenMany(other).map(..)....then();   

    }

 

}