首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >HttpComponents HttpClient连接池(7)-重试

HttpComponents HttpClient连接池(7)-重试

作者头像
TA码字
发布于 2020-04-07 08:16:36
发布于 2020-04-07 08:16:36
2K00
代码可运行
举报
文章被收录于专栏:TA码字TA码字
运行总次数:0
代码可运行

上一篇文章里我们介绍了 httpclient 连接池中空闲连接的清理,在这里我们主要介绍 http 连接的重试机制。

http连接的重试

httpclient 连接池也支持请求的重试,即在请求失败的情况下进行重试,对于重试设计以下几个关键点。

  1. 如何开启重试
  2. 如何定义重试次数
  3. 如何进行重试

如何开启重试

在 httpclient 连接池中,连接发送请求的重试是由 HttpRequestRetryHandler 类型的对象来处理,在HttpClientBuilder 有方法 disableAutomaticRetries() 来关闭重试,默认情况下重试是开启的,所以如果希望禁止重试那么就调用此方法。然后对于HttpClientBuilder 在构建 httpclient 的时候会根据这设置来确定 HttpRequestRetryHandler ,核心代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if (!automaticRetriesDisabled) {
    HttpRequestRetryHandler retryHandlerCopy = this.retryHandler;
if (retryHandlerCopy == null) {
        retryHandlerCopy = DefaultHttpRequestRetryHandler.INSTANCE;
    }
    execChain = new RetryExec(execChain, retryHandlerCopy);
}
  • httpclient 默认是开启重试机制的,如果希望关闭重试,则在构造中调用 HttpClientBuilder 的 disableAutomaticRetries() 方法。
  • 构造过程中如果开启了重试,那么则设置对象实例 HttpRequestRetryHandler 来负责重试。
  • HttpRequestRetryHandler 可以通过 Builder 对象来在外部设置。
  • 如果没有设置 HttpRequestRetryHandler 实例, 那么默认的为 DefaultHttpRequestRetryHandler 类型。

如何定义重试次数

如果使用默认重试机制,那么重试次数定义在 DefaultHttpRequestRetryHandler 对象实例中,其核心代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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);
    }
}
  • 在 DefaultHttpRequestRetryHandler 对象的默认构造函数中重试次数为 3。
  • 同时定义发生什么类型的 Exception 不会进行重试,在默认构造函数中所定义的这些异常类型为InterruptedIOException/UnknownHostException/ConnectException/SSLExcetion 。

如何进行重试

重试的过程定义在 RetryExec 对象实例的 execute() 方法里,其核心代码为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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;
            }
        }
}
  • 根据设置的重试次数进行循环发 http 请求,如果出现 IOException 则进行重试尝试。
  • 如果请求 abort ,则取消重试。
  • 对于请求 abort 的定义, 是指调了以前文章介绍的 ManagedHttpClientConnection 类型对象的shutdown 方法,绕过 TCP4 次握手关闭 socket 连接,直接设置 linger 通过发送 RST(reset) 包来快速关闭连接,核心代码如下:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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();
        }
    }
}
  • 如果 retryHandler 决定重试,那么就进行下一次重试,然后重试次数减 1。
  • 对于 DefaultHttpRequestRetryHandler 对象实例决定是否重试逻辑如下:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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;
}
  • 如何到达重试次数则不重试。
  • 如果请求 abort 则不重试。
  • 如果发生的异常在 retryHanlder 不进行重试的异常名单里或者是名单里的实例,则不重试。在默认构造函数之中所定义的这些异常类型为InterruptedIOException/UnknownHostException/ConnectException/SSLExcetion 。
  • 如果是 idempotent 幂等类型请求则重试, get 为幂等类型请求。
  • 如果是请求没有发出去或者 retryHandler 的 requestSentRetryEnabled 属性为 true 则重试,该值默认为 false 。
  • 除以上情况外的其他情况均不重试。

目前先写到这里,在下一篇文章里我们开始介绍 httpclient 连接池对于 ssl 支持。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-04-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 TA码字 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
云服务器安装纯净版 Debian 系统(从网络安装)
各大云厂商提供了种类繁多的系统镜像,也带来了各种全家桶,这里介绍一种简单的方法来安装Debian官方版纯净系统。
若海
2022/12/06
6.9K2
云服务器安装 AlpineLinux 系统(从网络安装)
各大云厂商提供了种类繁多的系统镜像,但唯独这个小巧可爱的Alpine无人问津。不过也难不倒咱们这些具有折腾精神的极客们。
若海
2022/12/06
9.2K5
CentOS服务器环境备份方案:将已搭建好的系统打包成镜像
操作系统:CentOS Linux release 7.9.2009 (Core)
小新笔记坊
2025/06/06
2550
Reinstalling Alpine Linux on a Lighthouse Instance
Create an instance with Debian or whatever flavour of your choice. Log in.
用户9453034
2022/02/16
1K0
Reinstalling Alpine Linux on a Lighthouse Instance
Linux系统自定义制作ISO安装镜像
在CentOS6系列版本系统在安装完成后会自动生成一个install.log文件,然后在CentOS7系列版本中就变化为anaconda-ks.cfg文件,它可以作为类似于Windows自动化安装的应答文件,只不过此处是用于Linux系统自动化安装的应答文件即无人值守自动化安装配置文件;
全栈工程师修炼指南
2022/09/29
12.1K0
从CentOS7.6升级到Rocky9.1镜像制作总结
卸载旧的epel仓库,重新安装epel仓库,删除冲突软件包,重装rpmconf并执行rpmconf,在交互界面一直输入Y和回车即可
用户4303685
2023/07/14
3.7K0
cobbler配置「建议收藏」
cobbler的网址为https://IP/cobbler_web 账户名和密码都为默认的cobbler
全栈程序员站长
2022/11/01
1.3K0
cobbler配置「建议收藏」
Centos7.6操作系统安装及优化全纪录
下载链接:http://isoredirect.centos.org/centos/7/isos/x86_64/
loong576
2019/09/10
5K0
Centos7.6操作系统安装及优化全纪录
腾讯云服务器操作系统TencentOS安装与体验
TencentOS Server( 又名Tencent Linux 简称Tlinux) 是腾讯针对云的场景研发的 Linux 操作系统,提供了专门的功能特性和性能优化,为云服务器实例中的应用程序提供高性能,且更加安全可靠的运行环境。Tencent Linux 使用免费,在 CentOS(及发行版)上开发的应用程序可直接在 Tencent Linux 上运行,用户还可持续获得腾讯云的更新维护和技术支持。
yuanfan2012
2020/10/10
27.5K0
腾讯云服务器操作系统TencentOS安装与体验
云服务器 Linux 手动 DD 安装第三方 Linux 发行版:原理与实战
云厂商提供的 Linux 服务器,发行版本总是比较有限,好在我们可以使用 dd 的方式:在“救援模式”上,手动安装第三方 Linux 发行版;亦或者挂载云硬盘作为启动盘,装载 Linux 的 ISO 镜像对系统盘进行安装。
Mintimate
2025/06/10
2080
云服务器 Linux 手动 DD 安装第三方 Linux 发行版:原理与实战
Android termux免root安装docker
https://zsxwz.com/2022/03/05/termux%e5%85%8droot%e5%ae%89%e8%a3%85docker/
治电小白菜
2024/02/05
4.5K0
Linux系统自定义制作ISO安装镜像
在CentOS6系列版本系统在安装完成后会自动生成一个install.log文件,然后在CentOS7系列版本中就变化为anaconda-ks.cfg文件,它可以作为类似于Windows自动化安装的应答文件,只不过此处是用于Linux系统自动化安装的应答文件即无人值守自动化安装配置文件;
全栈工程师修炼指南
2020/10/26
17K0
从CentOS官网下载系统镜像详细教程[通俗易懂]
CentOS(Community Enterprise Operating System,社区企业操作系统)是一个基于Red Hat Linux 提供的可自由使用源代码的企业级Linux发行版本,以高效、稳定著称。它使用与Red Hat相同的源代码编译而成,而且是开源免费的,因此有些要求高度稳定性的服务器以CentOS替代商业版的Red Hat Enterprise Linux使用,是很多中小服务器站点的首选。CentOS拥有Red Hat的所有功能,它们的不同之处在于CentOS并不包含封闭源代码软件,即Red Hat提供的额外的商业服务。
全栈程序员站长
2022/08/18
10.9K0
从CentOS官网下载系统镜像详细教程[通俗易懂]
Gentoo Linux x86快速安装指南对grub引导不成功的补救措施
Gentoo Linux x86快速安装指南 参考文档如下: http://www.gentoo.org/doc/zh_cn/gentoo-x86-quickinstall.xml#doc_chap2 1,在mirrors.163.com上下载 install-x86-minimal-20120710.iso设置光盘引导 2,到安装grub,这块要做更改,因为哪里漏掉了initrd这块没有写,所以导致系统重启时启动不起来 这时其实数据已经保存在sda硬盘上了,这时我们只需要重启用光盘引导挂上就好了 l
三杯水Plus
2018/11/14
1.3K0
云服务器安装kali linux
第一种方法: 通过挂载云硬盘到云服务器上,将kali镜像刻录到挂载的云硬盘中,利用VNC可视化安装kali系统;查看详情
LuckySec
2022/11/02
26K2
云服务器安装kali linux
kubernetes(二十)SpringCloud微服务容器化迁移
详情参考: https://blog.csdn.net/qinaye/article/details/82840625
alexhuiwang
2020/09/23
1.6K0
kubernetes(二十)SpringCloud微服务容器化迁移
pxe 安装配置大全
x86_64(amd ryzen 7 4800u):vmware workstation V16.1.2
Amadeus
2022/10/25
2.8K0
pxe 安装配置大全
常用的 Linux 系统备份、恢复命令
删库跑路的事常常听说,不过,这只能是个调侃的话题,真正的工作中可不能这么干,否则,库是删了,路怕是跑不了了。
杰哥的IT之旅
2021/01/06
5K0
在DigitalOcean的服务器上用官方Kali镜像构建系统
DigitalOcean是一家类似于AWS,Microsoft Azure,Google Cloud Platform等的云提供商。他们提供不同的Linux发行版实例,这些实例被称之为“droplets”。与AWS类似,DigitalOcean在世界各地都有数据中心,甚至在有的国家拥有多个数据中心。
FB客服
2019/07/29
1.8K0
完整部署CentOS7.2+OpenStack+kvm 云平台环境(4)--用OZ工具制作openstack镜像
在部署openstack云平台环境的时候,需要上传镜像到glance。 首先下载iso镜像,这里下载了centos6.5镜像,放到/usr/local/src目录下 然后用OZ工具制作openstack的镜像 *******************************安装libvirt虚拟机软件**************************************** [root@openstack-server src]# yum install qemu-kvm libvirt libvirt
洗尽了浮华
2018/01/22
1.4K0
完整部署CentOS7.2+OpenStack+kvm 云平台环境(4)--用OZ工具制作openstack镜像
推荐阅读
相关推荐
云服务器安装纯净版 Debian 系统(从网络安装)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档