写点什么

HttpClient 的两种重试机制

作者:Java高工P7
  • 2021 年 11 月 11 日
  • 本文字数:1580 字

    阅读完需:约 5 分钟

HttpRequestRetryHandler retryHandlerCopy = this.retryHandler;


if (retryHandlerCopy == null) {


retryHandlerCopy = DefaultHttpRequestRetryHandler.INSTANCE;


}


execChain = new RetryExec(execChain, retryHandlerCopy);


}


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


DefaultHttpRequestRetryHandler 主要有三个成员变量


retryCount


requestSentRetryEnabled


nonRetriableClasses


默认的实例变量设置如下


retry


【一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


Count=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();

用户头像

Java高工P7

关注

还未添加个人签名 2021.11.08 加入

还未添加个人简介

评论

发布
暂无评论
HttpClient的两种重试机制