HttpClient 出现 failed to respond 异常解决

这篇具有很好参考价值的文章主要介绍了HttpClient 出现 failed to respond 异常解决。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

今天碰到一个问题,httpclient 在使用线程池时,偶尔出现 NoHttpResponseException 异常。

httpclient org.apache.http.NoHttpResponseException: host:端口 failed to respond

经过一轮排查可能的原因是两个:我们属于第二个

原因

直接原因:服务器收到请求以后,不处理直接丢弃。
实际情况:
1.当服务端由于负载过大等情况发生时,可能会导致在收到请求后无法处理(比如没有足够的线程资源),会直接丢弃链接而不进行处理。此时客户端就会报错:NoHttpResponseException。
解决建议:
重试

2.客户端与服务端建立的请求在服务端已经失效。(例如:服务端 springboot 内置 tomcat 默认 keepAliveTimeout :20s,客户端自定义 keepAliveTimeout :30s,客户端连接池中取出的空闲连接可能已经被服务端失效,再次从连接池拿该失效连接进行请求时,就会报错。)
解决建议:
检查并关闭失效连接

解决方案

1.设置重试策略,这种要求服务端端接口是幂等的,但是业务反馈实际上请求的业务已经执行,所以我们不能重试。

HttpClient httpClient = HttpClients.custom()
        .setConnectionManager(connectionManager)
         // 问题一解决方案:设置重试
        .setRetryHandler(new MyRetryHandler()) 
         // 问题二解决方案:调整 keepAliveTimeout,这样无法复用长连接
        .setKeepAliveStrategy(myStrategy)
        .setDefaultRequestConfig(requestConfig)
        .setDefaultConnectionConfig(connectionConfig)
        .build();

2、设置校验机制(不百分百有效)

当每次拿到链接后会校验链接是否还建立,在validateAfterInactivity时间内不重复校验(默认两秒),比如,validateAfterInactivity设置的是5s,上次使用链接是在1s前,则不会校验直接使用 httpClientConnectionManager.setValidateAfterInactivity(5000);

HttpClient连接池-使用建议

对于 httpclient 连接池使用一般考虑以下几点:

  • 向连接池申请连接的超时时间
  • 连接建立的超时时间,即 socket 进行 3 次握手建立连接的超时时间
  • 连接超时时间,即 socket 读写超时时间
  • 设置最大 redirect 次数
  • 是否开启可用性检查
  • global 连接池中最大的连接数
  • individual route 连接池中最大的连接数
  • 请求重试次数
  • 设置ssl 请求的证书 trust 策略和 cn host name 验证策略
  • 开启对于空闲连接以及过期连接的清理,设置空闲连接的时长
  • 是否重用池化对象以及使用长连接

我们通过如下代码设置上述 items :

RequestConfig requestConfig = RequestConfig.custom()
                    .setConnectionRequestTimeout(10000)//设置连接池申请连接的超时时间,默认-1为无限时间
                    .setConnectTimeout(5000)//设置socket进行3次握手建立连接的超时时间
                    .setSocketTimeout(8000)//设置连接超时时间,即socket读写超时时间
                    .setMaxRedirects(50)//设置最大的redirect次数,默认为50
                    .setStaleConnectionCheckEnabled(Boolean.TRUE)//设置开启可用性检查,默认不开启
                    .build();

CloseableHttpClient htttpClient = HttpClients.custom()
                    .setDefaultRequestConfig(requestConfig)
                    .setMaxConnPerRoute(50)//设置individual route连接池中最大的连接数,默认为2
                    .setMaxConnTotal(500)//设置global连接池中最大的连接数,默认为20
                    .setConnectionTimeToLive(-1, TimeUnit.MICROSECONDS)//设置连接池中连接存活时间,默认-1代表无限存活,连接使用之后由response header "Keep-Alive: timeout"决定。
                    .evictIdleConnections(60000, TimeUnit.MILLISECONDS)//开启空袭连接清理线程,设置连接池中连接最大空闲时间,以及连接清理线程的sleep时间,默认为10秒
                    .evictExpiredConnections()//开启过期连接清理线程,过期时间默认为-1,连接使用后由response header "Keep-Alive: timeout"决定。
                    //.setRetryHandler(retryHandler)//设置重试策略,默认3次重试
                    //.setSSLContext(sslContext)//设置ssl请求上下文
                    //.setSSLHostnameVerifier(hostnameVerifier)//设置ssl证书cn host name验证策略,默认为验证cn host name
                    .build();

如果希望重用池化对象并且保持长连接,那么务必请调用 EntityUtils 类之中的静态方法toByteArray(),toString(),consume(),consumeQuietly()等。如果不希望重用池化对象,同时也不希望使用长连接,那么请调用 CloseableHttpResponse 的close() 方法。另外我们也会经常使用 Spring 的 RestTemplate 来发送 https 请求,对于 RestTemplate 一般也是会去整合 Apache HttpComponents HttpClient 组件,所以在使用 RestTemplate 的时候也请考虑以上各个 items 的设置。

原理篇

    1、org.apache.http.conn.HttpClientConnectionManager​​​​​​​

线程安全。

    httpclient中给出的实现类有两个:

        1)org.apache.http.impl.conn.BasicHttpClientConnectionManager

* A connection manager for a single connection. This connection manager maintains only one active
* connection. Even though this class is fully thread-safe it ought to be used by one execution
* thread only, as only one thread a time can lease the connection at a time.

        文档讲的很明白的,单链接管理类,对每个HttpRoute只保持一个有效链接,在实际项目中没有使用经验,不做评论。

PoolingHttpClientConnectionManager中的两个常用属性:

PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
connectionManager.setDefaultMaxPerRoute(DEFAULT_MAX_PER_ROUTE);
connectionManager.setMaxTotal(DEFAULT_SOCKET_MAX_TOTAL);

            MaxTotal:整个连接池的最大连接数

            DefaultMaxPerRoute:单个HttpRoute最大连接数,项目中假如只连接一个route那么可以设置为等于MaxTotal

2、org.apache.http.client.config.RequestConfig

这个类属性很多,所以使用了典型的构建器模式,通过内部类RequestConfig.Builder的build()方法来创建RequestConfig对象。

            一段典型的创建RequestConfig的代码

RequestConfig requestConfig = RequestConfig.custom()
        .setConnectTimeout(DEFAULT_CONNECT_TIMEOUT)
        .setConnectionRequestTimeout(DEFAULT_REQUEST_TIMEOUT)
        .setSocketTimeout(DEFAULT_SOCKET_TIMEOUT)
        .setStaleConnectionCheckEnabled(true).build();

            几个常用的属性:

                ConnectTimeout:建立连接的超时时间

                ConnectionRequestTimeout:从连接池中获取连接超时时间

                SocketTimeout:socket传输超时时间

                StaleConnectionCheckEnabled:是否启用检查失效连接,这个属性在4.4版本中被PoolingHttpClientConnectionManager中的#setValidateAfterInactivity(int)替换掉了。

所以,这里是我们可以用到的。

3、org.apache.http.impl.client.HttpClientBuilder

使用HttpClientBuilder类的静态方法create()创建HttpClientBuilder对象,将我们之前创建的PoolingHttpClientConnectionManager和RequestConfig对象通过setter方法设置给HttpClientBuilder,调用HttpClientBuilder对象的工厂方法build()来构建我们需要使用的httpclient对象,一段典型示例代码如下:

CloseableHttpClient httpClient = HttpClientBuilder.create().setConnectionManager(connectionManager)
        .setDefaultRequestConfig(requestConfig).build();

    在构建我们的httpclient对象之前,HttpClientBuilder中还有其他的一些配置需要我们注意,

        setRetryHandler:设置重试策略,httpclient对象默认使用org.apache.http.impl.client.DefaultHttpRequestRetryHandler类维护的本类静态实例INSTANCE,重试3次,并且在请求已经完整发送的情况下不重试。

        disableAutomaticRetries:禁用自动重试,如果此项设置为true,那么将忽略已经设置的RetryHandler。

        另外还有重定向策略,keepalive策略,cookiestore等等,可以根据项目需要进行设置。

三、项目中使用httpclient​​​​​​​

 1、HttpClient实例:

    httpclient中使用的PoolingHttpClientConnectionManager是线程安全的,httpclient也是线程安全的,在我们的项目中可以只维护一个httpclient对象,频繁的创建httpclient对象并不明智。通过设置PoolingHttpClientConnectionManager中的属性来保证性能。

    2、快速创建默认配置的httpclient对象:

    使用4.3版本中的org.apache.http.impl.client.HttpClients类的工厂方法来创建。

CloseableHttpClient closeableHttpClient = HttpClients.createDefault();

     以上方法创建的httpclient对象,所有配置都将使用默认值:

        PoolingHttpClientConnectionManager的默认配置

            DefaultMaxPerRoute=2

            MaxTotal=20

        RequestConfig的默认配置:

this.staleConnectionCheckEnabled = false;
this.redirectsEnabled = true;
this.maxRedirects = 50;
this.relativeRedirectsAllowed = true;
this.authenticationEnabled = true;
this.connectionRequestTimeout = -1;
this.connectTimeout = -1;
this.socketTimeout = -1;
this.contentCompressionEnabled = true;

3、详细的自定义配置创建httpclient对象,以下为一段示例代码,其中添加了https信任所有证书的操作

​​​​​​​

 private static final int DEFAULT_CONNECT_TIMEOUT = 2000;
    private static final int DEFAULT_REQUEST_TIMEOUT = 1000;
    private static final int DEFAULT_SOCKET_TIMEOUT = 10000;
    private static final int DEFAULT_SOCKET_MAX_TOTAL = 200;
    private static final int DEFAULT_MAX_PER_ROUTE = 200;
    private CloseableHttpClient httpClient;
    @PostConstruct
    public void init() {
        SSLConnectionSocketFactory sslsf = null;
        final SSLContext sslcontext;
        try {
            sslcontext = SSLContexts.custom().loadTrustMaterial(null, new TrustStrategy() {
                @Override
                public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    return true;
                }
            }).build();
            sslsf = new SSLConnectionSocketFactory(sslcontext,
                    SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
        } catch (final SecurityException | KeyStoreException | NoSuchAlgorithmException | KeyManagementException ignore) {
        }

        final Registry<ConnectionSocketFactory> sfr = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.getSocketFactory())
                .register("https", sslsf != null ? sslsf : SSLConnectionSocketFactory.getSocketFactory())
                .build();

        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(sfr);
        connectionManager.setDefaultMaxPerRoute(DEFAULT_MAX_PER_ROUTE);
        connectionManager.setMaxTotal(DEFAULT_SOCKET_MAX_TOTAL);
        RequestConfig requestConfig = RequestConfig.custom()
                .setAuthenticationEnabled(false)
                .setConnectTimeout(DEFAULT_CONNECT_TIMEOUT)
                .setConnectionRequestTimeout(DEFAULT_REQUEST_TIMEOUT)
                .setSocketTimeout(DEFAULT_SOCKET_TIMEOUT)
                .setStaleConnectionCheckEnabled(true).build();
        //默认重试策略,重试3次
        httpClient = HttpClientBuilder.create().setConnectionManager(connectionManager)
                .setDefaultRequestConfig(requestConfig).build();
    }

参考:

1、https://www.cnblogs.com/zjdxr-up/p/14530875.html

2、HttpComponents HttpClient连接池(10)-使用建议 - 腾讯云开发者社区-腾讯云 

3、HttpClient的详细配置指南(基于HttpClient 4.3.5)_chenghui7393的博客-CSDN博客文章来源地址https://www.toymoban.com/news/detail-473189.html

到了这里,关于HttpClient 出现 failed to respond 异常解决的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Ubuntu出现Failed to Fetch的解决办法

    在使用apt install XXX时出现问题: 由于没有配置好国内的镜像源。 解决方法: ①查看自己Ubuntu的版本: (LSB是Linux Standard Base(Linux标准库)的缩写,  lsb_release命令  用来与具体Linux发行版相关的Linux标准库信息) 获取版本号后进入https://mirrors.tuna.tsinghua.edu.cn/help/ubuntu/ ②选取

    2024年01月17日
    浏览(38)
  • 【异常解决】(一)解决docker报错failed to compute cache key: “...“ not found

    本文章仅做记录异常用途 使用.net core右键LY.ProductSchedularService.Api自动生成dockerfile 并使用 构建镜像时,报错提示: failed to compute cache key: “/App/LY/NetCore/LY.Common/LY.Common.csproj” not found: not found DockerFile如下 原因分析: Dockerfile不能跟LY.ProductSchedularService.Api项目同级的,因为该项

    2024年02月11日
    浏览(48)
  • 出现Failed to download metadata for repo ‘AppStream‘问题解决

    Linux学习笔记总结(一百零四)-Centos8出现Failed to download metadata for repo \\\'AppStream\\\'问题解决 大家都知道Centos8于2021年年底停止了服务,大家再在使用yum源安装时候,出现下面错误“错误:Failed to download metadata for repo \\\'AppStream\\\': Cannot prepare internal mirrorlist: No URLs in mirrorlist” 最终原因

    2024年02月16日
    浏览(52)
  • 出现failed to load steamui.dll如何解决?好的修复方法推荐

    当你电脑突然出现failed to load steamui.dll的时候,你是否一脸懵逼?根本不知道发生啥时候,突然就会这样报错,其实造成这个原因,主要是因为问题出在steam上,我们还是有很多种方法可以解决的,今天我们就来了解一下出现failed to load steamui.dll如何解决?   修复failed to load

    2024年02月05日
    浏览(60)
  • SpringBoot项目出现Failed to configure a DataSource错误时解决方法

     若在运行SpringBoot项目时,出现如下错误: 出现该错误的原因是:没有连接数据库,需要在application.properties(下图)中添加配置数据库的代码:  配置数据库的代码为:  添加完毕后,即可成功运行。

    2024年02月13日
    浏览(47)
  • 使用pdfjs报错:Failed to load module script: Expected a JavaScript module script but the server responded

    MIME 类型设置不正确: 服务器返回的文件 MIME 类型不正确。浏览器期望模块脚本的 MIME 类型为 application/javascript。如果服务器返回的 MIME 类型不是这个,浏览器会拒绝加载它,并显示这个错误 在nginx的默认mime.types文件中没有为mjs扩展名设置条目,这意味着它将被作为applicati

    2024年04月27日
    浏览(54)
  • 软件测试|解决 Git Push 出现 “error: failed to push some refs to“错误

    问题介绍 在使用Git推送代码到远程仓库时,我们可能会遇到以下错误消息之一: 这个错误通常发生在我们尝试将本地分支的更改推送到远程仓库时。这篇文章将详细解释可能导致此错误的原因以及如何解决它。 原因分析 这个错误通常有以下几种原因: 远程仓库的分支比本

    2024年02月08日
    浏览(54)
  • smiley-http-proxy-servlet做代理application/x-www-form-urlencoded请求类型,报错failed to respond

    关于springboot项目用来做类型nginx的反向代理,利用smiley-http-proxy-servlet既可以做出, 但是如果请求application/x-www-form-urlencoded 会报错failed to respond,对此我前后梳理原因并做出解决 引入依赖 编写动态生成prpxyServlet,通过yml配置,动态生成 yml配置 获取配置信息 编写动态生成prp

    2024年04月08日
    浏览(63)
  • 解决:git出现Failed to connect to 127.0.0.1 port 1080 Connection refused 的报错

    使用git将代码push到远程仓库时,一直都出现端口代理的问题。 完成了以上两个步骤后,还是没有解决,但是报错的信息发生了变化。出现了如下的错误。 ​ 结果如下图,检查出有网络问题,需要解决网络问题。 一.需要在hosts文件中添加映射 1.hosts文件存在于: C:WindowsSy

    2024年02月15日
    浏览(66)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包