spring webflux过滤器

    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头,如果没有则将请求转到/auth/error,由对应的controller进行处理。

@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 

               */ 

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

    }

 

}  

猜你喜欢

转载自wanshi.iteye.com/blog/2409097