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

Spring WebClient未发起请求问题(Java 1.8+Spring Boot 2.7.4)

问题分析与解决方案

核心原因:响应式流的惰性求值

WebClient基于Reactor框架,返回的Mono<String>是惰性求值的——只有调用订阅方法(比如subscribe()、block())时,才会实际发起HTTP请求。你的代码仅创建了Mono对象但未触发订阅,所以请求根本没执行,自然看不到代理日志和证书错误。

修复步骤

1. 触发请求订阅

在创建Mono<String> response后,添加订阅操作:

  • 同步场景(比如main方法)用block()阻塞等待结果:
String result = response.block();
System.out.println("返回结果: " + result);
  • 异步场景用subscribe()处理结果/异常:
response.subscribe(
    result -> System.out.println("返回结果: " + result),
    error -> System.err.println("请求失败: " + error.getMessage())
);

注意:main方法执行完会立刻退出,用异步订阅时要加延迟让线程等待请求完成:

try {
    Thread.sleep(5000); // 等待5秒确保请求执行完毕
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
}

2. 修复JSON字符串拼接问题

你代码里的JSON字符串拼接存在语法错误(换行符未转义),会导致编译失败或无效JSON。推荐两种更安全的方式:

  • 手动写转义后的JSON:
BodyInserters.fromValue("{\"email\": \"test\", \"password\": \"test\"}")
  • 用Jackson序列化对象(更规范,避免拼写错误):
    先定义DTO类:
public class LoginRequest {
    private String email;
    private String password;

    // 构造器、getter/setter
    public LoginRequest(String email, String password) {
        this.email = email;
        this.password = password;
    }

    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    public String getPassword() { return password; }
    public void setPassword(String password) { this.password = password; }
}

再传入对象序列化:

bodySpec.body(BodyInserters.fromValue(new LoginRequest("test", "test")))

Spring Boot默认集成Jackson,会自动将对象转为JSON。

3. 证书问题处理(请求发起后可能遇到)

当请求实际执行后,你大概率会遇到证书验证错误(目标是测试域名)。测试环境可临时禁用证书验证(生产环境绝对禁止):

// 创建信任所有证书的SslContext
SslContext sslContext = SslContextBuilder
    .forClient()
    .trustManager(InsecureTrustManagerFactory.INSTANCE)
    .build();

// 配置HttpClient使用自定义SslContext
HttpClient httpClient = HttpClient.create()
    .secure(t -> t.sslContext(sslContext));

// 构建WebClient
WebClient client = WebClient.builder()
    .clientConnector(new ReactorClientHttpConnector(httpClient))
    .baseUrl("https://test.caido.ro")
    .build();

Spring Boot 2.7.x默认已包含io.projectreactor.netty:reactor-netty依赖,无需额外引入。

完整修复后的代码示例

@SpringBootApplication
public class RestApplication {
    public static void main(String[] args) {
        System.out.println("开始构建请求");

        // 测试环境跳过证书验证
        SslContext sslContext = SslContextBuilder
                .forClient()
                .trustManager(InsecureTrustManagerFactory.INSTANCE)
                .build();
        HttpClient httpClient = HttpClient.create().secure(t -> t.sslContext(sslContext));

        WebClient client = WebClient.builder()
                .clientConnector(new ReactorClientHttpConnector(httpClient))
                .baseUrl("https://test.caido.ro")
                .build();

        RequestHeadersSpec<?> headersSpec = client.post()
                .uri("/api/login")
                .body(BodyInserters.fromValue(new LoginRequest("test", "test")));

        System.out.println("开始发送请求");
        // 同步阻塞获取结果
        try {
            String response = headersSpec.retrieve().bodyToMono(String.class).block();
            System.out.println("返回结果: " + response);
        } catch (Exception e) {
            System.err.println("请求失败: " + e.getMessage());
        }
        System.out.println("请求完成");
    }

    static class LoginRequest {
        private String email;
        private String password;

        public LoginRequest(String email, String password) {
            this.email = email;
            this.password = password;
        }

        public String getEmail() { return email; }
        public void setEmail(String email) { this.email = email; }
        public String getPassword() { return password; }
        public void setPassword(String password) { this.password = password; }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 13:30:42