1. 简介

本文将深入探讨如何在 Spring WebClient 中一次性设置多个请求头。WebClient 是 Spring WebFlux 框架的核心组件,支持同步和异步 HTTP 请求。我们将先解析 WebClient 的请求头处理机制,再通过代码示例演示三种批量设置请求头的实用方案。

2. WebClient 的请求头处理机制

HTTP 请求头本质是元数据,承载认证信息、内容类型、版本号等关键数据。在 WebClient 中,HttpHeaders 类负责管理这些请求头,它实现了 MultiValueMap<String, String> 接口,允许单个请求头键对应多个值(如 Accept 头)。这种设计完美支持需要多值请求头的场景。

⚠️ 关键点:HttpHeaders 是 Spring 专门为 HTTP 请求/响应头设计的类,不是普通的 Map 实现。

3. 批量设置请求头的三种方案

根据使用场景,我们可以选择为单个请求设置、全局默认设置或动态修改请求头。下面通过代码示例逐一说明。

3.1. 为单个请求设置请求头

当不同接口需要不同请求头时,直接在请求中设置最简单粗暴。以下测试用例演示了如何添加两个自定义请求头,并通过 MockWebServer 验证请求头是否正确发送:

@Test
public void givenRequestWithHeaders_whenSendingRequest_thenAssertHeadersAreSent() throws Exception {
    mockWebServer.enqueue(new MockResponse().setResponseCode(HttpStatus.OK.value()));

    WebClient client = WebClient.builder()
      .baseUrl(mockWebServer.url("/").toString())
      .build();

    ResponseEntity<Void> response = client.get()
      .headers(headers -> {
          headers.put("X-Request-Id", Collections.singletonList(RANDOM_UUID));
          headers.put("Custom-Header", Collections.singletonList("CustomValue"));
      })
      .retrieve()
      .toBodilessEntity()
      .block();

    assertNotNull(response);
    assertEquals(HttpStatusCode.valueOf(HttpStatus.OK.value()), response.getStatusCode());

    RecordedRequest recordedRequest = mockWebServer.takeRequest();
    assertEquals(RANDOM_UUID, recordedRequest.getHeader("X-Request-Id"));
    assertEquals("CustomValue", recordedRequest.getHeader("Custom-Header"));
}

实现原理:通过 headers(Consumer<HttpHeaders>) 方法,使用 Lambda 表达式操作 HttpHeaders 实例。这种函数式接口设计让请求头修改变得极其灵活。

3.2. 全局设置默认请求头

当所有请求都需要相同请求头时(如认证信息),在 WebClient 构建时设置默认请求头能避免重复代码。注意:这些默认值可被单个请求覆盖:

WebClient client = WebClient.builder()
  .baseUrl(mockWebServer.url("/").toString())
  .defaultHeaders(headers -> {
      headers.put("X-Request-Id", Collections.singletonList(RANDOM_UUID));
      headers.put("Custom-Header", Collections.singletonList("CustomValue"));
  })
  .build();

踩坑提醒:全局请求头会自动添加到所有请求,但若单个请求设置了同名头,会覆盖全局值而非合并。

3.3. 动态修改请求头(ExchangeFilterFunction)

需要运行时动态调整请求头时(如根据请求参数生成签名),使用 ExchangeFilterFunction 是最佳选择:

ExchangeFilterFunction dynamicHeadersFilter = (request, next) -> next.exchange(ClientRequest.from(request)
  .headers(headers -> {
      headers.put("X-Request-Id", Collections.singletonList(RANDOM_UUID));
      headers.put("Custom-Header", Collections.singletonList("CustomValue"));
  })
  .build());

注册过滤器到 WebClient:

WebClient client = WebClient.builder()
  .baseUrl(mockWebServer.url("/").toString())
  .filter(dynamicHeadersFilter)
  .build();

高级技巧:可叠加多个过滤器实现复杂逻辑(如认证+日志+签名),且过滤器执行顺序与注册顺序一致。

4. 总结

Spring WebClient 提供了三种灵活的请求头管理方案:

  • 单个请求设置:适用于接口差异化的场景
  • 全局默认设置:减少重复代码,保证一致性
  • 动态过滤器:满足运行时修改需求

根据实际需求选择合适方案,既能提升开发效率,又能避免请求头配置混乱。完整示例代码可在 GitHub 获取。


原始标题:Set Multiple Headers at Once in Spring WebClient | Baeldung