现象
httpclient 在使用线程池时,偶尔出现 NoHttpResponseException 异常。
httpclient org.apache.http.NoHttpResponseException: host:端口 failed to respond
异常由 httpclient 抛出:
httpcomponents-client/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/HttpRequestRetryExec.java
if (ex instanceof NoHttpResponseException) {
final NoHttpResponseException updatedex = new NoHttpResponseException(
route.getTargetHost().toHostString() + " failed to respond");
updatedex.setStackTrace(ex.getStackTrace());
throw updatedex;
}
原因
直接原因:服务器收到请求以后,不处理直接丢弃。
实际情况:
1.当服务端由于负载过大等情况发生时,可能会导致在收到请求后无法处理(比如没有足够的线程资源),会直接丢弃链接而不进行处理。此时客户端就会报错:NoHttpResponseException。
解决建议:
重试
2.客户端与服务端建立的请求在服务端已经失效。(例如:服务端 springboot 内置 tomcat 默认 keepAliveTimeout :20s,客户端自定义 keepAliveTimeout :30s,客户端连接池中取出的空闲连接可能已经被服务端失效,再次从连接池拿该失效连接进行请求时,就会报错。)
解决建议:
关闭失效连接(修改关闭空闲连接时间)
解决
1.设置重试策略。
HttpClient httpClient = HttpClients.custom()
.setConnectionManager(connectionManager)
// 问题一解决方案:设置重试
.setRetryHandler(new MyRetryHandler())
// 问题二解决方案:调整 keepAliveTimeout
.setKeepAliveStrategy(myStrategy)
.setDefaultRequestConfig(requestConfig)
.setDefaultConnectionConfig(connectionConfig)
.build();
// TODO : 待填坑