如何在Spring WebClient中一次性设置多个头部?

33

我试图为我的REST客户端设置头文件,但每次都需要编写

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

如何使用headers()方法同时设置所有标题?


1
阅读 headers(Consumer<HttpHeaders> headersConsumer) 方法的 API。您可以提供一个 Consumer<HttpHeaders>,该方法可以使用 HttpHeaders 的任何 MultiValueMap 方法。 - Phil
1
@Phil,产品负责人正在寻找“供应商”,而不是“消费者”。 - Tiina
4个回答

47

如果这些标头需要每个请求都更改,您可以使用:

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

这样做并不能节省太多敲击键盘的时间;所以对于那些在每次请求中都不会改变的头部信息,您可以在构建客户端时将其设置为默认头部:

WebClient webClient = WebClient.builder().defaultHeader("...", "...").build();
WebClient webClient = WebClient.builder().defaultHeaders(httpHeaders -> {
    httpHeaders.setX("");
    httpHeaders.setY("");
}).build();

无法理解 httpHeaders -> {} 部分,请您能否给出一个适当的例子来解释一下? - Lahiru Liyanage
3
这是一个很好的例子,事实上,它是一个非常非常好的例子。如果你不理解它,你可能需要研究lambda和函数接口。如果你刚开始学习,不要期望它会很快学会,第一次掌握它很难 :) - PlickPlick
@PlickPlick,你知道是否有什么可以用作网络拦截器的东西,以便在WebClient请求返回401 UNAUTHORIZED时调用逻辑刷新令牌,然后重新调用最后一次调用吗? - Christian Blanco
检查 onSuccess onError 和 onErrorResume。https://www.baeldung.com/spring-webflux-errors - PlickPlick
但��我其实不太确定你所说的网络拦截器是什么意思。而且我最近才开始使用Web客户端,可能不是合适的人来问。 - PlickPlick

7

消费者是正确的,尽管很难想象,特别是在您使用WebClient构建后,您可以继续使用其他流畅的组合方法调用,完成对标题的操作。

假设您有一个HttpHeaders(或MutliValue Map)在范围内持有您的标头。这里是一个示例,使用来自Spring Cloud Gateway的Exchange对象:

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

addAll可以接收多值映射,如果这好理解的话。如果不理解,可以让你的IDE来指导你。

为了使消费者更清晰明了,请按以下方式重新编写:

private Consumer<HttpHeaders> getHttpHeadersFromExchange(ServerWebExchange exchange) {
    return httpHeaders -> {
        httpHeaders.addAll(exchange.getRequest().getHeaders());
    };
}
.
.
.
webclient.get().uri("blah-blah")
    .headers(getHttpHeadersFromExchange(exchange))
    ...

3

我发现这个问题再次出现在我身上,这一次我正在使用WebClient直接编写groovy。同样,我尝试驱动的示例是使用Consumer作为headers方法调用的参数。

在groovy中,额外的问题是groovy闭包语法和java lambda语法都使用->

这里是groovy版本:

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)

Java版本在这里:

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

这是一个非常有用的响应,因为它声明了一个接口,并展示了一个带有链接多值映射作为参数的Java Lambda表达式的示例。 - berlot83

2
在Spring Boot 2.7.5中:
webClient
  .get()
    .uri("blah-blah")
      .headers(
        httpHeaders -> {
          httpHeaders.set("key1", "value1");
          httpHeaders.set("key2", "value2");
        })

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接