Gateway 网关 之 自定义过滤器


接口 ServerWebExchange:

关于 过滤器 相关接口解说请看:  https://www.cnblogs.com/fdzang/p/11812348.html

 

ServerWebExchange的注释: ServerWebExchange是一个HTTP请求-响应交互的契约。提供对HTTP请求和响应的访问,并公开额外的服务器端处理相关属性和特性,如请求属性。

 

其实,ServerWebExchange命名为服务网络交换器,存放着重要的请求-响应属性、请求实例和响应实例等等,有点像Context的角色。

 

 

public interface ServerWebExchange {

    // 日志前缀属性的KEY,值为org.springframework.web.server.ServerWebExchange.LOG_ID
    // 可以理解为 attributes.set("org.springframework.web.server.ServerWebExchange.LOG_ID","日志前缀的具体值");
    // 作用是打印日志的时候会拼接这个KEY对饮的前缀值,默认值为""
    String LOG_ID_ATTRIBUTE = ServerWebExchange.class.getName() + ".LOG_ID";
    String getLogPrefix();

    // 获取ServerHttpRequest对象
    ServerHttpRequest getRequest();

    // 获取ServerHttpResponse对象
    ServerHttpResponse getResponse();
    
    // 返回当前exchange的请求属性,返回结果是一个可变的Map
    Map<String, Object> getAttributes();
    
    // 根据KEY获取请求属性
    @Nullable
    default <T> T getAttribute(String name) {
        return (T) getAttributes().get(name);
    }
    
    // 根据KEY获取请求属性,做了非空判断
    @SuppressWarnings("unchecked")
    default <T> T getRequiredAttribute(String name) {
        T value = getAttribute(name);
        Assert.notNull(value, () -> "Required attribute '" + name + "' is missing");
        return value;
    }

     // 根据KEY获取请求属性,需要提供默认值
    @SuppressWarnings("unchecked")
    default <T> T getAttributeOrDefault(String name, T defaultValue) {
        return (T) getAttributes().getOrDefault(name, defaultValue);
    } 

    // 返回当前请求的网络会话
    Mono<WebSession> getSession();

    // 返回当前请求的认证用户,如果存在的话
    <T extends Principal> Mono<T> getPrincipal();  
    
    // 返回请求的表单数据或者一个空的Map,只有Content-Type为application/x-www-form-urlencoded的时候这个方法才会返回一个非空的Map -- 这个一般是表单数据提交用到
    Mono<MultiValueMap<String, String>> getFormData();   
    
    // 返回multipart请求的part数据或者一个空的Map,只有Content-Type为multipart/form-data的时候这个方法才会返回一个非空的Map  -- 这个一般是文件上传用到
    Mono<MultiValueMap<String, Part>> getMultipartData();
    
    // 返回Spring的上下文
    @Nullable
    ApplicationContext getApplicationContext();   

    // 这几个方法和lastModified属性相关
    boolean isNotModified();
    boolean checkNotModified(Instant lastModified);
    boolean checkNotModified(String etag);
    boolean checkNotModified(@Nullable String etag, Instant lastModified);
    
    // URL转换
    String transformUrl(String url);    
   
    // URL转换映射
    void addUrlTransformer(Function<String, String> transformer); 

    // 注意这个方法,方法名是:改变,这个是修改ServerWebExchange属性的方法,返回的是一个Builder实例,Builder是ServerWebExchange的内部类
    default Builder mutate() {
         return new DefaultServerWebExchangeBuilder(this);
    }

    interface Builder {      
         
        // 覆盖ServerHttpRequest
        Builder request(Consumer<ServerHttpRequest.Builder> requestBuilderConsumer);
        Builder request(ServerHttpRequest request);
        
        // 覆盖ServerHttpResponse
        Builder response(ServerHttpResponse response);
        
        // 覆盖当前请求的认证用户
        Builder principal(Mono<Principal> principalMono);
    
        // 构建新的ServerWebExchange实例
        ServerWebExchange build();
    }
}

 

 

 

 


全局过滤器:

全局过滤器不需要工厂,也不需要配置,直接对所有的路由都生效。

可以使用GlobalFilter实现统一的权限验证日志记录 等 希望对所有代理的项目都生效的内容都可以配置在全局过滤器中。

且在项目中可以配置多个 GlobalFilter 的实现类。都可以自动执行;多个过滤器,按照 Ordered  的顺序规则 顺序执行

全局过滤器有两个主要 接口 :GlobalFilter, Ordered   Ordered 定义全局过滤器的执行顺序的,数字越大,越后执行

主要结构:

@Component
public class MyLogGlobalFilter implements GlobalFilter {
   private Logger logger = LoggerFactory.getLogger(MyLogGlobalFilter.class);
 
   @Override
   public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
      // 前置过滤器逻辑
      logger.info("执行全局过滤器-logger");
      long start = System.currentTimeMillis();
 
      // 执行后续逻辑
      Mono<Void> result = chain.filter(exchange);
 
      // 后置过滤器逻辑
      long end = System.currentTimeMillis();
 
      logger.info("执行结束,本次执行时长:{} 毫秒", end - start);
 
      return result;
   }
}

 

如:以下简单示例:

@Component
public class GlobalLogFilter implements GlobalFilter, Ordered {
 
    /**
     * 实现自定义过滤器的逻辑
     *
     * @param exchange 请求的上下文对象
     * @param chain    通道
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("进入全局过滤器");
        ServerHttpRequest request = exchange.getRequest();
        String username = request.getQueryParams().getFirst("username");
        if (null == username) {
            System.out.println("请求参数中没有 username,不允许访问");
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();
        }
        // 传递给下一个过滤链
        return chain.filter(exchange);
    }
 
    /**
     * 加载过滤器的顺序,数字越小,优先级越高
     * 最小数:int HIGHEST_PRECEDENCE = -2147483648;
     * 最大数:int LOWEST_PRECEDENCE = 2147483647;
     *
     * @return
     */
    @Override
    public int getOrder() {
        return -1000;
    }
}

 


自定义 FilterFactory

 可以定义针对于 Router 的 Filter。

注意:

1、类名必须叫做XxxGatewayFilterFactory.注入到Spring容器后使用时的名称就叫做Xxx。

2、类必须继承 AbstractGatewayFilterFactory,让父类帮实现配置参数的处理 ( 不限麻烦的可以直接实现 GatewayFilterFactory )

3、所有需要传递进来的参数都配置到当前类的内部类Config中

 

@Component
// 自定义路由过滤器,查看请求路径地址
public class RequestPathGatewayFilterFactory extends AbstractGatewayFilterFactory<RequestPathGatewayFilterFactory.MyConfig> {
 
   public RequestPathGatewayFilterFactory() {
      super(MyConfig.class);
   }
 
   /**
    * 这个简化配置的方案,当前方法返回简化配置参数明明列表
    * 如:RequestPath=nameValue,pathValue
    *
    * @return
    */
   @Override
   public List<String> shortcutFieldOrder() {
      return Arrays.asList("name", "path");
   }
 
   /**
    * 执行过滤的逻辑
    *
    * @param config
    * @return
    */
   @Override
   public GatewayFilter apply(MyConfig config) {
      // 匿名内部类方式实现
      return (ServerWebExchange exchange, GatewayFilterChain chain) -> {
         // 前置逻辑器逻辑
         String path = exchange.getRequest().getPath().toString();
         System.out.println("路由过滤器,本次请求地址为:" + path + ",配置的参数是:" + config.getName() + ",配置的 path=" + config.getPath());
 
         // 同样可以对后置处理的响应进行处理
         ServerHttpResponse response = exchange.getResponse();
 
         // 执行下一个逻辑
         return chain.filter(exchange);
 
         //后置过滤器逻辑
      };
 
   }
 
   @Getter
   // 当前过滤器是要使用的配置内容
   public static class MyConfig {
 
      private String name;
      private String path;
 
      public MyConfig setName(String name) {
         this.name = name;
         return this;
      }
 
      public MyConfig setPath(String path) {
         this.path = path;
         return this;
      }
   }
}

 

使用时配置:(  重写了  shortcutFieldOrder() 方法,可以进行简化配置使用 )

 

 

filters:
  RequestPath=testnameValue,testPathValue

 

>>>>>>>>>>>>>  下一篇 : https://www.cnblogs.com/chxlay/p/15150599.html    <<<<<<<<<<<<<<<<<<<<<<

 
posted @ 2021-08-17 00:16  Vermeer  阅读(1026)  评论(0)    收藏  举报