在上一篇文章里我们介绍了 httpclient 连接池中空闲连接的清理,在这里我们主要介绍 http 连接的重试机制。
http连接的重试
httpclient 连接池也支持请求的重试,即在请求失败的情况下进行重试,对于重试设计以下几个关键点。
如何开启重试
在 httpclient 连接池中,连接发送请求的重试是由 HttpRequestRetryHandler 类型的对象来处理,在HttpClientBuilder 有方法 disableAutomaticRetries() 来关闭重试,默认情况下重试是开启的,所以如果希望禁止重试那么就调用此方法。然后对于HttpClientBuilder 在构建 httpclient 的时候会根据这设置来确定 HttpRequestRetryHandler ,核心代码如下:
if (!automaticRetriesDisabled) {
HttpRequestRetryHandler retryHandlerCopy = this.retryHandler;
if (retryHandlerCopy == null) {
retryHandlerCopy = DefaultHttpRequestRetryHandler.INSTANCE;
}
execChain = new RetryExec(execChain, retryHandlerCopy);
}
如何定义重试次数
如果使用默认重试机制,那么重试次数定义在 DefaultHttpRequestRetryHandler 对象实例中,其核心代码如下:
public static final DefaultHttpRequestRetryHandler INSTANCE = new DefaultHttpRequestRetryHandler();
public DefaultHttpRequestRetryHandler() {
this(3, false);
}
public DefaultHttpRequestRetryHandler(final int retryCount, final boolean requestSentRetryEnabled) {
this(retryCount, requestSentRetryEnabled, Arrays.asList(InterruptedIOException.class, UnknownHostException.class, ConnectException.class,SSLException.class));
}
protected DefaultHttpRequestRetryHandler(final int retryCount, final boolean requestSentRetryEnabled, final Collection<Class<? extends IOException>> clazzes) {
super();
this.retryCount = retryCount;
this.requestSentRetryEnabled = requestSentRetryEnabled;
this.nonRetriableClasses = new HashSet<Class<? extends IOException>>();
for (final Class<? extends IOException> clazz: clazzes) {
this.nonRetriableClasses.add(clazz);
}
}
如何进行重试
重试的过程定义在 RetryExec 对象实例的 execute() 方法里,其核心代码为:
for (int execCount = 1;; execCount++) {
try {
return this.requestExecutor.execute(route, request, context, execAware);
} catch (final IOException ex) {
if (execAware != null && execAware.isAborted()) {
this.log.debug("Request has been aborted");
throw ex;
}
if (retryHandler.retryRequest(ex, execCount, context)) {
if (this.log.isInfoEnabled()) {
this.log.info("I/O exception ("+ ex.getClass().getName() + ") caught when processing request to "+ route +": "+ ex.getMessage());
}
if (this.log.isDebugEnabled()) {
this.log.debug(ex.getMessage(), ex);
}
if (!RequestEntityProxy.isRepeatable(request)) {
this.log.debug("Cannot retry non-repeatable request");
throw new NonRepeatableRequestException("Cannot retry request " + "with a non-repeatable request entity", ex);
}
request.setHeaders(origheaders);
if (this.log.isInfoEnabled()) {
this.log.info("Retrying request to " + route);
}
} else {
if (ex instanceof NoHttpResponseException) {
final NoHttpResponseException updatedex = new NoHttpResponseException(route.getTargetHost().toHostString() + " failed to respond");
updatedex.setStackTrace(ex.getStackTrace());
throw updatedex;
}
throw ex;
}
}
}
public void shutdown() throws IOException {
final Socket socket = this.socketHolder.getAndSet(null);
if (socket != null) {
// force abortive close (RST)
try {
socket.setSoLinger(true, 0);
} catch (final IOException ex) {
// empty here
}
finally {
socket.close();
}
}
}
public boolean retryRequest(final IOException exception, final int executionCount, final HttpContext context) {
Args.notNull(exception, "Exception parameter");
Args.notNull(context, "HTTP context");
if (executionCount > this.retryCount) {
// Do not retry if over max retry count
return false;
}
if (this.nonRetriableClasses.contains(exception.getClass())) {
return false;
}
for (final Class<? extends IOException> rejectException : this.nonRetriableClasses) {
if (rejectException.isInstance(exception)) {
return false;
}
}
final HttpClientContext clientContext = HttpClientContext.adapt(context);
final HttpRequest request = clientContext.getRequest();
if(requestIsAborted(request)){
return false;
}
if (handleAsIdempotent(request)) {
// Retry if the request is considered idempotent
return true;
}
if (!clientContext.isRequestSent() || this.requestSentRetryEnabled) {
// Retry if the request has not been sent fully or
// if it's OK to retry methods that have been sent
return true;
}
// otherwise do not retry
return false;
}
目前先写到这里,在下一篇文章里我们开始介绍 httpclient 连接池对于 ssl 支持。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有