我有一个web服务,它接受一个带有XML的POST方法.它工作正常,然后在一些随机的场合,它无法与服务器通信抛出IOException与消息The target server failed to respond
.后续调用工作正常.
它主要发生在我打电话然后让我的应用程序闲置10-15分钟时.我之后的第一个调用会返回此错误.
我尝试了几件事......
我设置重试处理程序就像
HttpRequestRetryHandler retryHandler = new HttpRequestRetryHandler() {
public boolean retryRequest(IOException e, int retryCount, HttpContext httpCtx) {
if (retryCount >= 3){
Logger.warn(CALLER, "Maximum tries reached, exception would be thrown to outer block");
return false;
}
if (e instanceof org.apache.http.NoHttpResponseException){
Logger.warn(CALLER, "No response from server on "+retryCount+" call");
return true;
}
return false;
}
};
httpPost.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, retryHandler);
Run Code Online (Sandbox Code Playgroud)
但这次重试从未被召唤过.(是的,我正在使用right instanceof子句).虽然调试这个类永远不会被调用.
我甚至尝试过设置HttpProtocolParams.setUseExpectContinue(httpClient.getParams(), false);
但没有用.有人可以建议我现在能做什么吗?
重要 除了弄清楚为什么我得到例外之外,我所关注的一个重要问题是为什么重试操作员不在这里工作?
ok2*_*k2c 102
最有可能由连接管理器保持活动的持久连接变得陈旧.也就是说,目标服务器在其端部关闭连接,而HttpClient无法对该事件作出反应,同时连接处于空闲状态,从而使连接半关闭或"失效".通常这不是问题.HttpClient采用多种技术来验证从池中租用的连接有效性.即使禁用过时连接检查并且使用过时连接来传输请求消息,请求执行通常在使用SocketException的写操作中失败并自动重试.但是在某些情况下,写操作可以在没有异常的情况下终止,随后的读操作返回-1(流结束).在这种情况下,HttpClient别无选择,只能假设请求成功,但服务器很可能由于服务器端的意外错误而无法响应.
解决这种情况的最简单方法是在一段时间不活动后驱逐已过时的连接和连接,这些连接和连接比池中的1分钟更长.有关详细信息,请参阅HttpClient教程的此部分.
Jeh*_*lio 17
接受的答案是对的,但缺乏解决方案.要避免此错误,您可以为此HTTP应用程序添加setHttpRequestRetryHandler(或apache组件4.4的setRetryHandler),如此答案中所示.
虽然接受的答案是正确的,但恕我直言,这只是一种解决方法。
需要明确的是:持久连接可能会变得陈旧,这是一种完全正常的情况。但不幸的是,当 HTTP 客户端库无法正确处理它时,情况就非常糟糕了。
由于 Apache HttpClient 中的这种错误行为多年来都没有得到修复,所以我肯定更愿意切换到可以轻松从过时连接问题中恢复的库,例如 OkHttp。
为什么?
NoHttpResponseException
)。当我切换到 OkHttp 时,我的问题就NoHttpResponseException
永远消失了。
如今,除非另有声明,否则大多数 HTTP 连接都被视为持久连接。然而,为了节省服务器资源,连接很少会永远保持打开状态,许多服务器的默认连接超时时间相当短,例如 Apache httpd 2.2 及更高版本的连接超时时间为 5 秒。
该org.apache.http.NoHttpResponseException
错误很可能是由服务器关闭的一个持久连接引起的。
可以设置 Apache Http 客户端池中未使用的连接保持打开状态的最长时间(以毫秒为单位)。
使用 Spring Boot,实现此目的的一种方法是:
public class RestTemplateCustomizers {
static public class MaxConnectionTimeCustomizer implements RestTemplateCustomizer {
@Override
public void customize(RestTemplate restTemplate) {
HttpClient httpClient = HttpClientBuilder
.create()
.setConnectionTimeToLive(1000, TimeUnit.MILLISECONDS)
.build();
restTemplate.setRequestFactory(
new HttpComponentsClientHttpRequestFactory(httpClient));
}
}
}
// In your service that uses a RestTemplate
public MyRestService(RestTemplateBuilder builder ) {
restTemplate = builder
.customizers(new RestTemplateCustomizers.MaxConnectionTimeCustomizer())
.build();
}
Run Code Online (Sandbox Code Playgroud)
小智 5
解决方案:将 ReuseStrategy 更改为 never
由于这个问题非常复杂,并且有很多不同的因素可能会失败,我很高兴在另一篇文章中找到这个解决方案:如何解决 org.apache.http.NoHttpResponseException
永远不要重用连接:在 org.apache.http.impl.client.AbstractHttpClient 中配置:
httpClient.setReuseStrategy(new NoConnectionReuseStrategy());
Run Code Online (Sandbox Code Playgroud)
可以在 org.apache.http.impl.client.HttpClientBuilder 构建器上配置相同的内容:
builder.setConnectionReuseStrategy(new NoConnectionReuseStrategy());
Run Code Online (Sandbox Code Playgroud)