30

I was trying to set headers to my rest client but every time I have to write

webclient.get().uri("blah-blah")
         .header("key1", "value1")
         .header("key2", "value2")...

How can I set all headers at the same time using headers() method?

Amit Kumar
  • 313
  • 1
  • 3
  • 4
  • 1
    Read the API for the [`headers(Consumer headersConsumer)`](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/reactive/function/client/WebClient.RequestHeadersSpec.html#headers-java.util.function.Consumer-) method. You provide a `Consumer` which can use any of the `MultiValueMap` methods of [`HttpHeaders`](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/http/HttpHeaders.html) – Phil Dec 02 '19 at 06:18
  • 1
    @Phil The PO is looking for a `Supplier` not a `Consumer` – Tiina Mar 25 '20 at 06:43

4 Answers4

44

If those headers change on a per request basis, you can use:

webClient.get().uri("/resource").headers(httpHeaders -> {
    httpHeaders.setX("");
    httpHeaders.setY("");
});

This doesn't save much typing; so for the headers that don't change from one request to another, you can set those as default headers while building the client:

WebClient webClient = WebClient.builder().defaultHeader("...", "...").build();
WebClient webClient = WebClient.builder().defaultHeaders(httpHeaders -> {
    httpHeaders.setX("");
    httpHeaders.setY("");
}).build();
Brian Clozel
  • 56,583
  • 15
  • 167
  • 176
  • cannot understand httpHeaders -> {} part.. can you explain it with a proper example please? – Lahiru Liyanage Jan 26 '21 at 13:54
  • 3
    This is a proper example actually it is a really really good one. If you do not understand it you probably need to look into lambda and functional interfaces. If just starting out do not expect it to be a quick thing to learn it is hard to grasp first time around it :) – PlickPlick Sep 16 '21 at 10:18
  • @PlickPlick, do you know if there is something that we can use as network interceptor in case the request of the WebClient returns a 401 UNAUTHORIZED? so we can call a logic to refresh tokens and then recall the last call? – Christian Blanco Sep 21 '21 at 20:06
  • Check onSuccess onError and onErrorResume. https://www.baeldung.com/spring-webflux-errors – PlickPlick Sep 22 '21 at 21:19
  • But I'm actually not really sure what you mean by network interceptor. Also I have resently started using webclients so probably not the right guy to ask – PlickPlick Sep 22 '21 at 21:26
7

The consumer is correct, though it's hard to visualize, esp. in that you can continue with additional fluent-composition method calls in the webclient construction, after you've done your work with the headers.

....suppose you have a HttpHeaders (or MutliValue map) holding your headers in scope. here's an example, using an exchange object from spring cloud gateway:

final HttpHeaders headersFromExchangeRequest = exchange.getRequest().headers();
webclient.get().uri("blah-blah")
    .headers( httpHeadersOnWebClientBeingBuilt -> { 
         httpHeadersOnWebClientBeingBuilt.addAll( headersFromExchangeRequest );
    }
)...

the addAll can take a multivalued map. if that makes sense. if not, let your IDE be your guide.

to make the consumer clearer, let's rewrite the above as follows:

private Consumer<HttpHeaders> getHttpHeadersFromExchange(ServerWebExchange exchange) {
    return httpHeaders -> {
        httpHeaders.addAll(exchange.getRequest().getHeaders());
    };
}
.
.
.
webclient.get().uri("blah-blah")
    .headers(getHttpHeadersFromExchange(exchange))
    ...
Bob Makowski
  • 305
  • 2
  • 8
3

I found this problem came up again for me and this time I was writing groovy directly using WebClient. Again, the example I'm trying to drive is using the Consumer as the argument to the headers method call.

In groovy, the additional problem is that groovy closure syntax and java lambda syntax both use ->

The groovy version is here:

def mvmap = new LinkedMultiValueMap<>(headersAsMap)
def consumer = { it -> it.addAll(mvmap) } as Consumer<HttpHeaders>

WebClient client = WebClient.create(baseUrlAsString)
def resultAsMono = client.post()
        .uri(uriAsString).accept(MediaType.APPLICATION_JSON)
        .headers(consumer)
        .body(Mono.just(payload), HashMap.class)
        .retrieve()
        .toEntity(HashMap.class)

The java version is here:

LinkedMultiValueMap mvmap = new LinkedMultiValueMap<>(headersAsMap);
Consumer<HttpHeaders> consumer = it -> it.addAll(mvmap);

WebClient client = WebClient.create(baseUrlAsString);
Mono<ResponseEntity<HashMap>> resultAsMono = client.post()
        .uri(uriAsString).accept(MediaType.APPLICATION_JSON)
        .headers(consumer)
        .body(Mono.just(payload), HashMap.class)
        .retrieve()
        .toEntity(HashMap.class);
Bob Makowski
  • 305
  • 2
  • 8
  • This is a very usefull response, because declare an interface a shows an example of java lambda expresion with a linked multivalue map as a params. – berlot83 Aug 23 '22 at 12:28
2

In Spring Boot 2.7.5:

webClient
  .get()
    .uri("blah-blah")
      .headers(
        httpHeaders -> {
          httpHeaders.set("key1", "value1");
          httpHeaders.set("key2", "value2");
        })
Marco Lackovic
  • 6,077
  • 7
  • 55
  • 56