设置httpClient的超时时间及关闭自动重发

设置httpClient的超时时间及关闭自动重发

关于httpClient的重发策略

HttpClient默认是有重试机制的,其重试策略是:

1.只有发生IOExecetion时才会发生重试

2.InterruptedIOException、UnknownHostException、ConnectException、SSLException,发生这4中异常不重试

3.get方法可以重试3次,post方法在socket对应的输出流没有被write并flush成功时可以重试3次。

4.读/写超时不进行重试

5.socket传输中被重置或关闭会进行重试

一、HttpClient的创建方式:

//设置超时时间

httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(5000);

httpClient.getHttpConnectionManager().getParams().setSoTimeout(5000);

//构造PostMethod的实例 url:请求地址

PostMethod postMethod = new PostMethod(url);

//关闭重发策略

postMethod .getParams().setParameter(HttpMethodParams.RETRY_HANDLER,new DefaultHttpMethodRetryHandler(0,false));

//设置编码格式

postMethod .getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET,"UTF-8");

//设置超时时间

postMethod .getParams().setParameter(HttpMethodParams.SO_TIMEOUT,5000);

try{

httpClient.executeMethod(postMethod);

}catch (Exception e){

//TODO 省略异常处理部分

}finally {

postMethod.releaseConnection();

}

重试方法调用:

在 org.apache.commons.httpclient.HttpMethodDirector类中,如果发生IOException,会判断是否需要重试

具体源码如下:

private void executeWithRetry(HttpMethod method) throws IOException, HttpException {

int execCount = 0;

try {

while(true) {

++execCount;

try {

if (LOG.isTraceEnabled()) {

LOG.trace("Attempt number " + execCount + " to process request");

}

if (this.conn.getParams().isStaleCheckingEnabled()) {

this.conn.closeIfStale();

}

if (!this.conn.isOpen()) {

this.conn.open();

if (this.conn.isProxied() && this.conn.isSecure() && !(method instanceof ConnectMethod) && !this.executeConnect()) {

return;

}

}

this.applyConnectionParams(method);

method.execute(this.state, this.conn);

return;

} catch (HttpException var5) {

throw var5;

} catch (IOException var6) {

LOG.debug("Closing the connection.");

this.conn.close();

if (method instanceof HttpMethodBase) {

MethodRetryHandler handler = ((HttpMethodBase)method).getMethodRetryHandler();

if (handler != null && !handler.retryMethod(method, this.conn, new HttpRecoverableException(var6.getMessage()), execCount, method.isRequestSent())) {

LOG.debug("Method retry handler returned false. Automatic recovery will not be attempted");

throw var6;

}

}

HttpMethodRetryHandler handler = (HttpMethodRetryHandler)method.getParams().getParameter("http.method.retry-handler");

if (handler == null) {

handler = new DefaultHttpMethodRetryHandler();

}

if (!((HttpMethodRetryHandler)handler).retryMethod(method, var6, execCount)) {

LOG.debug("Method retry handler returned false. Automatic recovery will not be attempted");

throw var6;

}

if (LOG.isInfoEnabled()) {

LOG.info("I/O exception (" + var6.getClass().getName() + ") caught when processing request: " + var6.getMessage());

}

if (LOG.isDebugEnabled()) {

LOG.debug(var6.getMessage(), var6);

}

LOG.info("Retrying request");

}

}

} catch (IOException var7) {

if (this.conn.isOpen()) {

LOG.debug("Closing the connection.");

this.conn.close();

}

this.releaseConnection = true;

throw var7;

} catch (RuntimeException var8) {

if (this.conn.isOpen()) {

LOG.debug("Closing the connection.");

this.conn.close();

}

this.releaseConnection = true;

throw var8;

}

}

HttpMethodRetryHandler:

new DefaultHttpMethodRetryHandler(0,false)解读:

DefaultHttpMethodRetryHandler(0,false),

允许重试次数为0

调用如下方法:

public DefaultHttpMethodRetryHandler(int retryCount, boolean requestSentRetryEnabled) {

this.retryCount = retryCount;

this.requestSentRetryEnabled = requestSentRetryEnabled;

}

默认的重试方法:DefaultHttpMethodRetryHandler()

允许重试次数为3

具体处理如下“retryMethod”方法

若实际发送次数大于等于3次,不进行重试;

若实际发送次数小于3次,请求未成功发送,进行重试;

若实际发送次数小于3次,请求成功发送,不进行重试;

public class DefaultHttpMethodRetryHandler implements HttpMethodRetryHandler {

private static Class SSL_HANDSHAKE_EXCEPTION = null;

private int retryCount;

private boolean requestSentRetryEnabled;

public DefaultHttpMethodRetryHandler(int retryCount, boolean requestSentRetryEnabled) {

this.retryCount = retryCount;

this.requestSentRetryEnabled = requestSentRetryEnabled;

}

public DefaultHttpMethodRetryHandler() {

this(3, false);

}

public boolean retryMethod(HttpMethod method, IOException exception, int executionCount) {

if (method == null) {

throw new IllegalArgumentException("HTTP method may not be null");

} else if (exception == null) {

throw new IllegalArgumentException("Exception parameter may not be null");

} else if (method instanceof HttpMethodBase && ((HttpMethodBase)method).isAborted()) {

return false;

} else if (executionCount > this.retryCount) {

return false;

} else if (exception instanceof NoHttpResponseException) {

return true;

} else if (exception instanceof InterruptedIOException) {

return false;

} else if (exception instanceof UnknownHostException) {

return false;

} else if (exception instanceof NoRouteToHostException) {

return false;

} else if (SSL_HANDSHAKE_EXCEPTION != null && SSL_HANDSHAKE_EXCEPTION.isInstance(exception)) {

return false;

} else {

return !method.isRequestSent() || this.requestSentRetryEnabled;

}

}

}

MethodRetryHandler目前在commons-httpclient-3.1.jar中不推荐使用

public class DefaultMethodRetryHandler implements MethodRetryHandler {

private int retryCount = 3;

private boolean requestSentRetryEnabled = false;

public DefaultMethodRetryHandler() {

}

public boolean retryMethod(HttpMethod method, HttpConnection connection, HttpRecoverableException recoverableException, int executionCount, boolean requestSent) {

return (!requestSent || this.requestSentRetryEnabled) && executionCount <= this.retryCount;

}

}

二、CloseableHttpClient的创建方式:

1.HttpClients.custom().setXXX().build();

2.HttpClients.createDefault();

第一种方法用来定制一些HttpClient的属性,比如https证书,代理服务器,http过滤器,连接池管理器等自定义的用法。

第二种方法用来获得一个默认的HttpClient实例,获取到的CloseableHttpClient是默认重试策略的。

这两种方法获得都是CloseableHttpClient实例,且都是通过HttpClientBuilder的build()构建的。

HttpClients.custom();源码

public static HttpClientBuilder custom() {

return HttpClientBuilder.create();

}

HttpClients.createDefault();源码

public static CloseableHttpClient createDefault() {

return HttpClientBuilder.create().build();

}

如果要禁止CloseableHttpClient访问超时时进行重试,则需要用第一种方式创建CloseableHttpClient,设置重试参数automaticRetriesDisabled为true;

CloseableHttpClient build1 = HttpClients.custom().disableAutomaticRetries().build()

其中disableAutomaticRetries()的源码为:

public final HttpClientBuilder disableAutomaticRetries() {

this.automaticRetriesDisabled = true;

return this;

}

这里将参数设置为true,在执行build()方法的时候会进行判断:

if (!this.automaticRetriesDisabled) {

routePlannerCopy = this.retryHandler;

if (routePlannerCopy == null) {

routePlannerCopy = DefaultHttpRequestRetryHandler.INSTANCE;

}

execChain = new RetryExec((ClientExecChain)execChain, (HttpRequestRetryHandler)routePlannerCopy);

}

如果automaticRetriesDisabled为false就会进入if分支,使用RetryExec执行器创建执行链使用用默认的重发策略DefaultHttpRequestRetryHandler。因此automaticRetriesDisabled设置为true时就可以禁止重发。

为HttpClient设置连接超时时间和获取数据超时时间

使用HttpClient,一般都需要设置连接超时时间和获取数据超时时间。这两个参数很重要,目的是为了防止访问其他http时,由于超时导致自己的应用受影响。

4.5版本中,这两个参数的设置都抽象到了RequestConfig中,由相应的Builder构建。

setConnectTimeout:设置连接超时时间,单位毫秒。

setConnectionRequestTimeout:设置从connect Manager获取Connection 超时时间,单位毫秒。这个属性是新加的属性,因为目前版本是可以共享连接池的。

setSocketTimeout:请求获取数据的超时时间,单位毫秒。 如果访问一个接口,多少时间内无法返回数据,就直接放弃此次调用。

HttpPost httpPost = new HttpPost();

RequestConfig requestConfig = RequestConfig.custom().

setConnectTimeout(5000).

setConnectionRequestTimeout(5000).

setSocketTimeout(5000).

build();

httpPost.setConfig(requestConfig);

整体例子

/**

* 创建CloseableHttpClient,禁止超时重试,并设置超时时间

*/

CloseableHttpClient closeableHttpClient = HttpClients.custom().disableAutomaticRetries().build();

HttpPost httpPost = new HttpPost();

RequestConfig requestConfig = RequestConfig.custom().

setConnectTimeout(5000).

setConnectionRequestTimeout(5000).

setSocketTimeout(5000).

build();

httpPost.setConfig(requestConfig);

try {

closeableHttpClient.execute(httpPost);

} catch (IOException e) {

//异常处理部分省略.....

e.printStackTrace();

}

相关推荐

一文告诉你:为什么众多爱宠人士信赖可莉丝汀猫粮
谁有365体育投注网址

一文告诉你:为什么众多爱宠人士信赖可莉丝汀猫粮

📅 08-07 👁️ 7002
明日之后上架材料多久能看到 多久才能刷新出来
谁有365体育投注网址

明日之后上架材料多久能看到 多久才能刷新出来

📅 07-02 👁️ 3830
游戏内链接蓝色羽毛
直播365app下载

游戏内链接蓝色羽毛

📅 09-02 👁️ 716