Apache HttpClient 5.4.1版本超时配置不生效问题求助:如何用非废弃类实现3秒超时
Apache HttpClient 5.4.1版本超时配置不生效问题求助:如何用非废弃类实现3秒超时
嗨,我来帮你解决这个头疼的问题!你遇到的超时不生效,核心原因是手动创建的DefaultClientTlsStrategy没有继承全局配置的Socket超时参数,导致HTTPS连接的SO_TIMEOUT没有被正确设置为3秒,才会等接口的5秒响应结束后才触发超时。
修正后的非废弃类配置代码
基于你原来的代码修改,完全使用非废弃类就能实现3秒超时:
public class HttpClientTimeoutExamplePoolingHttpClientConnectionManagerBuilder { public static void main(String[] args) { try { // 用DefaultClientTlsStrategyBuilder构建TLS策略,同时绑定Socket超时配置 DefaultClientTlsStrategy tlsStrategy = DefaultClientTlsStrategyBuilder.create() .setSslContext(SSLContext.getDefault()) .setSocketConfig(SocketConfig.custom() .setSoTimeout(Timeout.of(3, TimeUnit.SECONDS)) .build()) .build(); final PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create() .setTlsSocketStrategy(tlsStrategy) // 全局默认Socket配置,覆盖非HTTPS连接的超时 .setDefaultSocketConfig(SocketConfig.custom() .setSoTimeout(Timeout.of(3, TimeUnit.SECONDS)) .build()) .setMaxConnPerRoute(20) .setMaxConnTotal(200) .build(); final RequestConfig requestConfig = RequestConfig.custom() .setConnectionRequestTimeout(Timeout.of(1, TimeUnit.SECONDS)) .setConnectTimeout(Timeout.of(3, TimeUnit.SECONDS)) .setResponseTimeout(Timeout.of(3, TimeUnit.SECONDS)) .build(); CloseableHttpClient httpClient = HttpClients.custom() .setConnectionManager(connectionManager) .setDefaultRequestConfig(requestConfig) .evictExpiredConnections() .build(); // Create GET request final HttpGet httpGet = new HttpGet("https://httpbin.org/delay/5"); httpGet.setConfig(requestConfig); // Log start time long startTime = System.currentTimeMillis(); System.out.println("Executing GET request at: " + startTime); try { CloseableHttpResponse response = httpClient.execute(httpGet); try { long endTime = System.currentTimeMillis(); System.out.println("Response received after: " + (endTime - startTime) + "ms"); System.out.println("Response status: " + response.getCode()); System.out.println("Response body: " + EntityUtils.toString(response.getEntity())); } finally { response.close(); } } catch (Exception e) { long endTime = System.currentTimeMillis(); System.out.println("Exception after: " + (endTime - startTime) + "ms"); System.out.println("Exception type: " + e.getClass().getName()); System.out.println("Exception message: " + e.getMessage()); e.printStackTrace(); } finally { httpClient.close(); } } catch (Exception e) { e.printStackTrace(); } } }
为什么这样修改能生效?
- 你之前直接创建
DefaultClientTlsStrategy时,没有传入自定义的SocketConfig,导致HTTPS连接使用了默认的SO_TIMEOUT(通常为0,即永不超时),所以会等接口的5秒响应结束。 - 现在用
DefaultClientTlsStrategyBuilder构建TLS策略,明确绑定了3秒的SO_TIMEOUT,让HTTPS连接遵守超时规则。 - 保留全局
setDefaultSocketConfig是为了确保非HTTPS的HTTP连接也能应用相同的超时配置。
更简洁的替代方案(无需手动处理TLS策略)
如果不需要自定义SSLContext,可以让连接管理器自动创建默认TLS策略,全局SocketConfig会自动应用到所有连接,代码更清爽:
final PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create() .setDefaultSocketConfig(SocketConfig.custom() .setSoTimeout(Timeout.of(3, TimeUnit.SECONDS)) .build()) .setMaxConnPerRoute(20) .setMaxConnTotal(200) .build();
这样就不用手动创建DefaultClientTlsStrategy,Builder会自动处理所有类型连接的配置,超时规则也能正常生效。
补充说明
ResponseTimeout是HttpClient层面的超时逻辑,它依赖于底层Socket的SO_TIMEOUT实现,所以确保SO_TIMEOUT正确设置是核心。- 你之前用废弃Registry方式生效,是因为旧的SocketFactory会直接读取连接管理器的DefaultSocketConfig,而手动创建的TLS策略没有继承这个配置,才导致了差异。
修改后,你的请求应该会在3秒左右触发超时,和用废弃类的效果完全一致,同时所有使用的类都是非废弃的。
备注:内容来源于stack exchange,提问作者newLearner




