You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WebClient POST请求jsonplaceholder报UnknownHostException求助

问题根因

这个报错和公网连通性、WebClient基础写法没有关系,核心原因是Eureka环境下的负载均衡逻辑劫持了WebClient的域名解析流程:

  • 你代码里手动new RestTemplate()能正常请求公网接口,是因为这个实例是直接实例化的,没有被Spring加上@LoadBalanced对应的负载均衡拦截器,走的是系统默认公网DNS解析逻辑。
  • 你的服务已经集成了Netflix Eureka和Spring Cloud负载均衡组件,只要类路径下存在WebClient依赖,Spring Cloud的自动配置会默认给WebClient的构造链注入负载均衡过滤器。这个过滤器的逻辑是把请求URI里的主机名默认当作Eureka注册中心里的服务ID,直接去注册中心拉取服务实例做负载均衡,完全跳过公网DNS解析。公网域名jsonplaceholder.typicode.com根本没有在你的Eureka集群注册,自然会抛出域名解析失败的异常。
解决方案

根据使用场景二选一即可:

方案1:拆分内外网专用WebClient实例(生产环境推荐)

不要直接调用全局WebClient.builder()构造所有WebClient实例,单独定义两类不同用途的Builder Bean,从根源上隔离内网服务调用和外网请求的逻辑:

  1. 在配置类中声明两个带不同标识的WebClient.Builder:
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;

@Configuration
public class WebClientConfig {
    // 用于调用Eureka集群内注册的服务,自动带负载均衡能力
    @Bean
    @LoadBalanced
    public WebClient.Builder lbWebClientBuilder() {
        return WebClient.builder();
    }

    // 用于调用公网/第三方外部服务,不加载负载均衡逻辑
    @Bean
    public WebClient.Builder externalWebClientBuilder() {
        return WebClient.builder();
    }
}
  1. 调用公网接口时,注入专门用于外部请求的externalWebClientBuilder构造WebClient,就会走正常公网DNS解析:
@Autowired
private WebClient.Builder externalWebClientBuilder;

// 构造请求客户端
WebClient client = externalWebClientBuilder
        .baseUrl("https://jsonplaceholder.typicode.com")
        .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
        .build();

方案2:临时构造实例时手动移除负载均衡过滤器

如果只是临时测试,不想额外定义配置Bean,可以在手动构造WebClient的时候,直接把注入的负载均衡过滤器移除即可:

import org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerExchangeFilterFunction;

WebClient client = WebClient.builder()
        .baseUrl("https://jsonplaceholder.typicode.com")
        .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
        // 移除自动注入的负载均衡过滤器
        .filters(filterList -> filterList.removeIf(
                filter -> filter.getClass().equals(LoadBalancerExchangeFilterFunction.class)
        ))
        .build();
额外优化建议

你当前手写JSON字符串传参的写法存在冗余,还容易出现转义错误。既然已经配置了JSON消息转换器,直接传原生Java/Map对象即可,WebClient会自动完成序列化:

// 不用手动拼JSON字符串,直接构造参数
Map<String, Object> reqBody = Map.of(
        "title", "foo",
        "body", "bar",
        "userId", 1
);

Mono<String> respMono = client.post()
        .uri("/posts")
        .bodyValue(reqBody)
        .retrieve()
        .bodyToMono(String.class);

String resp = respMono.block();

内容的提问来源于stack exchange,提问作者Ezani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 04:54:29