java失败重试机制_HttpClient的两种重试机制

scikitlearn tensorflow实用教材

71.1元

包邮

(需用券)

去购买 >

5ba567ca3302f5d321cf47349da47d69.png

本文基于HttpClient 4.5.13

使用 http 请求外部服务时,由于网络或者服务本身的不稳定性,经常需要重试。重试当然可以通过手撸代码实现,但更好的方式是通过现有的机制去实现。HttpClient 中支持两种重试:异常重试。

服务不可用重试。

异常重试

HttpClient 执行时会抛出两种异常:java.io.IOException

ClientProtocolException

java.io.IOException 被认为是非致命性且可恢复的,而 ClientProtocolException 被认为是致命性的,不可恢复。

处理的时候要注意,ClientProtocolException 是 java.io.IOException 的子类。

如果是这样创建 HttpClient 的CloseableHttpClient httpClient = HttpClients.custom().build();

异常重试是默认开启的,具体代码可以参考 HttpClientBuilder.build() 方法,下面是相关的代码// Add request retry executor, if not disabled

if (!automaticRetriesDisabled) {

HttpRequestRetryHandler retryHandlerCopy = this.retryHandler;

if (retryHandlerCopy == null) {

retryHandlerCopy = DefaultHttpRequestRetryHandler.INSTANCE;

}

execChain = new RetryExec(execChain, retryHandlerCopy);

}

automaticRetriesDisabled 是一个 boolean 类型的变量,默认为 false ,所以条件默认是成立的,如果没有设置 HttpRequestRetryHandler 就会用一个默认的。

DefaultHttpRequestRetryHandler主要有三个成员变量retryCount重试次数

requestSentRetryEnabled 是否可以在请求成功发出后重试,这里的成功是指发送成功,并不指请求成功。

nonRetriableClasses 不重试的异常类集合,如果异常为集合中指定的异常时,不会重试。

默认的实例变量设置如下retryCount=3,最多重试3次。

requestSentRetryEnabled=false,发送成功的就不会重试了

nonRetriableClasses包含了以下四种:InterruptedIOException

UnknownHostException

ConnectException

SSLException

重试的执行逻辑在org.apache.http.impl.execchain.RetryExec,有兴趣的可以去看下。

默认的是否重试逻辑如下@Override

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;

}

这里要注意下幂等方法,post 和 put 都不是,所以那里的判断不会成立,但是如果 requestSentRetryEnabled 设置为 true,还是会重发的,那就需要保证被调用的接口再处理 post 和 put 的请求时是幂等的。

有些人可能会遇到问题,比如报了 SocketTimeoutException 的异常,但是没有重试,这是因为 SocketTimeoutException 是 InterruptedIOException 的子类,默认会被忽略。如果需要重试,可以自定义一个 HttpRequestRetryHandler ,然后再设置就可以了。HttpClients.custom().setRetryHandler(httpRequestRetryHandler).build();

实际上使用的时候继承 DefaultHttpRequestRetryHandler,然后扩展一些自己的实现就很方便。

如果想禁用调重试也很简单HttpClients.custom().disableAutomaticRetries().build();

服务不可用重试

有的时候,请求成功了,但是 http 状态码可能不是 2xx,这种情况也需要重试。HttpClient中提供了在服务不可用时进行重试的机制。

重试执行的逻辑在 org.apache.http.impl.execchain.ServiceUnavailableRetryExec,有兴趣可以看下。

HttpClient中提供了默认的策略,但是没有默认开启,需要自己设置DefaultServiceUnavailableRetryStrategy serviceUnavailableRetryStrategy = new DefaultServiceUnavailableRetryStrategy();

httpClient = HttpClients.custom().setServiceUnavailableRetryStrategy(serviceUnavailableRetryStrategy).build();

重试的逻辑@Override

public boolean retryRequest(final HttpResponse response, final int executionCount, final HttpContext context) {

return executionCount <= maxRetries &&

response.getStatusLine().getStatusCode() == HttpStatus.SC_SERVICE_UNAVAILABLE;

}

当没有超过重试次数,且返回码为503的时候进行重试,当然也可以自定义 ServiceUnavailableRetryStrategy 来实现自己的需求。

另外还支持设置重试请求的间隔时间。

看到了这里一定是真爱了,关注微信公众号【码农张思壮】第一时间获取更新。

java 11官方入门(第8版)教材

79.84元

包邮

(需用券)

去购买 >

f0f3f55624fb396b1764d42d6df88864.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值