Spring Boot 3.2.2 RestClient首次调用API报I/O错误的解决及HTTP版本设置方法
问题解决方案
一、首次请求I/O错误的解决方案
该错误多因首次请求时TCP连接建立异常、第三方API服务冷启动,或RestClient默认连接配置不匹配导致,以下是可行解决办法:
配置连接池与超时参数
RestClient默认使用的SimpleClientHttpRequestFactory无连接池,首次请求需新建连接,易出现超时或连接异常。可切换至基于Apache HttpClient或OkHttp的连接池配置,同时设置合理超时时间:
示例代码(Apache HttpClient):@Bean public RestClient restClient() { HttpClient httpClient = HttpClientBuilder.create() .setMaxConnTotal(100) .setMaxConnPerRoute(20) .setConnectionTimeOut(Timeout.ofSeconds(5)) .setResponseTimeout(Timeout.ofSeconds(10)) .build(); ClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient); return RestClient.builder() .requestFactory(factory) .build(); }配置后连接会被复用,避免首次请求的连接建立问题。
添加重试机制
针对首次请求偶发失败的情况,给RestClient添加重试逻辑,可使用Spring的RetryTemplate实现:@Bean public RetryTemplate retryTemplate() { SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(); retryPolicy.setMaxAttempts(2); // 重试1次,共发起2次请求 FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy(); backOffPolicy.setBackOffPeriod(1000); // 间隔1秒重试 RetryTemplate retryTemplate = new RetryTemplate(); retryTemplate.setRetryPolicy(retryPolicy); retryTemplate.setBackOffPolicy(backOffPolicy); return retryTemplate; } // 调用时包裹请求逻辑 ResponseEntity<Response> responseEntity = retryTemplate.execute(context -> restClient.post() .uri("%s/veriy".formatted(config.getUrl())) .header("x-api-key", config.getKey()) .body(requestBody) .retrieve() .toEntity(Response.class) );检查第三方API连接要求
确认第三方API是否强制要求特定HTTP版本、是否需要开启Keep-Alive,或是否有IP白名单/初始验证机制,这些都可能导致首次请求失败。
二、RestClient中配置HTTP版本的方法
Spring Boot 3.2.2中,RestClient需通过自定义ClientHttpRequestFactory指定HTTP版本,以下是两种常见实现方式:
方式1:基于Apache HttpClient配置
@Bean public RestClient restClient() { HttpClient httpClient = HttpClientBuilder.create() .setVersion(HttpVersion.HTTP_1_1) // 可替换为HTTP_2 .build(); ClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient); return RestClient.builder() .requestFactory(factory) .build(); }
需提前引入Apache HttpClient依赖:
<dependency> <groupId>org.apache.httpcomponents.client5</groupId> <artifactId>httpclient5</artifactId> </dependency>
方式2:基于OkHttp配置
@Bean public RestClient restClient() { OkHttpClient okHttpClient = new OkHttpClient.Builder() .protocols(List.of(Protocol.HTTP_1_1)) // 指定HTTP版本 .build(); ClientHttpRequestFactory factory = new OkHttp3ClientHttpRequestFactory(okHttpClient); return RestClient.builder() .requestFactory(factory) .build(); }
需提前引入OkHttp依赖:
<dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> </dependency>
内容的提问来源于stack exchange,提问作者Nishant Charan
相关产品推荐
相关产品推荐

