
spring boot 中 webclient 的 defaultheaders 方法因使用了错误的 setter 方法(如 set 而非 add)导致请求头未被正确注入,本文详解两种可靠写法及关键注意事项,确保全局默认头稳定生效。
spring boot 中 webclient 的 defaultheaders 方法因使用了错误的 setter 方法(如 set 而非 add)导致请求头未被正确注入,本文详解两种可靠写法及关键注意事项,确保全局默认头稳定生效。
在 Spring Boot 应用中,WebClient 是推荐的响应式 HTTP 客户端。许多开发者期望通过 defaultHeaders() 或 defaultHeader() 一次性配置通用请求头(如 Content-Type 和自定义 API Key),从而避免在每个请求链中重复调用 .header()。但实践中常遇到“默认头未生效、服务返回 400 Bad Request”的问题——根本原因在于 defaultHeaders(Consumer
HttpHeaders#set(String, String) 会覆盖同名头的全部值,且对 Content-Type 这类特殊头有严格语义约束:当其值为空或格式非法时,WebClient 在实际发送请求前会静默跳过或触发底层验证失败(如 Netty 报 Invalid Content-Type),最终导致服务端拒绝请求(HTTP 400)。而 defaultHeaders 回调接收的是一个空的、尚未初始化的 HttpHeaders 实例,此时调用 header.setContentType(...) 实际等价于 headers.set(HttpHeaders.CONTENT_TYPE, ...),极易引发异常。
✅ 正确做法是使用 add() 或选用更安全的 defaultHeader() 重载方法:
方案一:在 defaultHeaders 中使用 add()
this.webClient = WebClient.builder()
.baseUrl(baseURL)
.defaultHeaders(headers -> {
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
headers.add("api-key", apiKey);
})
.build();
方案二(推荐):使用链式 defaultHeader()(类型安全、无歧义)
this.webClient = WebClient.builder()
.baseUrl(baseURL)
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.defaultHeader("api-key", apiKey)
.build();
⚠️ 注意事项:
- defaultHeader(String, Object...) 内部自动调用 add(),支持多值(如多个 Accept 头),且完全规避 set() 的副作用;
- Content-Type 值必须为字符串形式(即 MediaType.APPLICATION_JSON_VALUE,而非 MediaType.APPLICATION_JSON 对象);
- 若需动态 header(如 token 刷新),应改用 filter(ExchangeFilterFunction) + ClientRequest.from() 构建新请求,而非依赖静态默认头;
- 避免在 defaultHeaders 中调用 set(), setAll(), clear() 等可能破坏头完整性或引入空值的方法。
修复后,您原有的 getAllNetworks() 方法无需任何改动即可正常工作,请求将自动携带 Content-Type: application/json 和 api-key:











