Search code examples
spring-bootoauth-2.0spring-webfluxspring-webclient

Webflux Webclient: Is there a way to use lets say 2 different filter chains on a webclient?


Lets assume that I need to post certain data and the headers that needs to be added to my current webclient request method is conditional(Depends on some header values i.e. if a certain header is present in the upstream call then I need to add some more headers in my current request else the happy story). Any idea, how can we configure this?

Assuming request is my incoming call from upstream. Current weblclient configuration

                   webClient.post()
                            .uri(request.destination())
                            .header(// Some header value here)
                            .header(// Some header value here)
                            .headers(// More headers from upstream)
                            .body(BodyInserters.fromValue(request.data()))
                            .retrieve()
                            .bodyToMono(//);

Solution

  • If I understood your question correctly, the point is how to chain several filters.

    If you look at the source code of Webclient, you can see the following:

      public WebClient.Builder filter(ExchangeFilterFunction filter) {
        Assert.notNull(filter, "ExchangeFilterFunction must not be null");
        this.initFilters().add(filter);
        return this;
      }
    
      public WebClient.Builder filters(Consumer<List<ExchangeFilterFunction>> filtersConsumer) {
        filtersConsumer.accept(this.initFilters());
        return this;
      }
    
      private List<ExchangeFilterFunction> initFilters() {
        if (this.filters == null) {
          this.filters = new ArrayList();
        }
    
        return this.filters;
      }
    

    You can add different filters which not related together directly, just there are contained in a list. When you send a request, it will be run it is affected the chain orders list position (or use andThen method). Note that this is a lambda.

      public WebClient build() {
        ClientHttpConnector connectorToUse = this.connector != null ? this.connector : this.initConnector();
        ExchangeFunction exchange = this.exchangeFunction == null ? ExchangeFunctions.create(connectorToUse, this.initExchangeStrategies()) : this.exchangeFunction;
    
        
        ExchangeFunction filteredExchange = this.filters != null ? (ExchangeFunction)this.filters.stream().reduce(ExchangeFilterFunction::andThen).map((filter) -> {
          return filter.apply(exchange); // <-- Here. 
        }).orElse(exchange) : exchange;
     
        HttpHeaders defaultHeaders = this.copyDefaultHeaders();
        MultiValueMap<String, String> defaultCookies = this.copyDefaultCookies();
        return new DefaultWebClient(filteredExchange, this.initUriBuilderFactory(), defaultHeaders, defaultCookies, this.defaultRequest, new DefaultWebClientBuilder(this));
      }