服务端keep-alive超时断开连接

spring resttemplate使用apache httpclient4.4 连接池。
主要是因为httpclient之前与服务端建立的连接断开,但是没有通知客户端或者客户端还没有收到通知,导致下次请求该服务时httpclient继续使用该连接导致报错。
服务端tomcat 默认的keep-alive timeout :60s,httpclient的连接池中设置的时间大于60s,连接空闲时间超过60s后再次从连接池拿出进行请求时,就会出现failed to respond异常。

服务器端负载过大,丢弃链接

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

可以通过tcp报文分析出,客户端和服务器连接的最大空闲时间,看看报文的交互过程。
在这里插入图片描述

  • 注意到图中第2882个包,服务器返回前一个请求的响应完成(10:16:25),到第2888个包(10:16:46)客户端发送的下一个请求包。直接有21s的空闲间隔,结合多个完整的连接请求断开的时间,可以判断出服务器在美国连接空闲20s后自动就会发起断开连接。
  • 客户端发出的第2888个包在收到服务器发送的2891个FIN包之前,客户端发送了2888和2889两个请求报文(客户端此时为收到服务器FIN报文)。但发送后,服务端发送的FIN包立刻就到了客户端,可以推测出,服务端在发送FIN报文前还没有收到客户端的请求报文,但是刚刚发送FIN报文却没有收到[FIN、ACK]报文,因此服务器无法判断是否是正常结束,所有就发出来RST包,关闭连接。
  • 客户端使用的httpclient的60s的长连接发送请求,使用的http1.1协议默认的keepalive的,同一个线程的多个请求可以复用同一个长连接。正是由于服务器发出的FIN包的时间与客户端在连接空闲了20s时扔使用这个连接发送数据时之间微秒的时间差(服务器发送了FIN报文,但是客户端还没有收到,但是客户端已经发送了请求数据包),所以导致出现NoHttpResponseException异常。

客户端捕获异常重试(推荐)

推荐使用重发机制。
http请求使用重发机制,捕获NohttpResponseException的异常,重新发送请求,重发3次后还是失败才停止。由于服务器不知道客户端捕获到NohttpResponseException这个异常后,客户端是否已经关闭这个连接,因此每次重发都需要建立连接请求。新建连接不存在太长的空闲时间问题。

客户端增加KeepAliveStrategy策略

配置keepAlive策略,目的是让客户端在服务端还没有发送断开连接报文时,客户端提前发送断开连接请求。
即客户端的keepAlive时间要配置的比服务端的keepAlive小(服务端默认:keepAlive 60s)。

@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder
                .setConnectTimeout(Duration.ofMillis(1000)) // 连接建立超时时间
                .setReadTimeout(Duration.ofMillis(2000)) // 响应数据超时时间
                .requestFactory(this::requestFactory) // 请求工厂
                .build();
    @Bean
    public HttpComponentsClientHttpRequestFactory requestFactory() {
        PoolingHttpClientConnectionManager connectionManager =
                new PoolingHttpClientConnectionManager(30, TimeUnit.SECONDS);
        connectionManager.setMaxTotal(200);
        connectionManager.setDefaultMaxPerRoute(20);
        CloseableHttpClient httpClient = HttpClients.custom()
                .setConnectionManager(connectionManager)
                .evictIdleConnections(30, TimeUnit.SECONDS)
                .disableAutomaticRetries()
                // 有 Keep-Alive 认里面的值,没有的话永久有效
                //.setKeepAliveStrategy(DefaultConnectionKeepAliveStrategy.INSTANCE)
                // 换成自定义的
                .setKeepAliveStrategy(new CustomConnectionKeepAliveStrategy())
                .build();
        HttpComponentsClientHttpRequestFactory requestFactory =
                new HttpComponentsClientHttpRequestFactory(httpClient);
        return requestFactory;
     * KeepAlive策略
    public class CustomConnectionKeepAliveStrategy implements ConnectionKeepAliveStrategy {
        // 连接超过20s没有数据就主动断开与服务器的连接
        private final long DEFAULT_SECONDS = 20;
        @Override
        public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
            long timeOut = Arrays.asList(response.getHeaders(HTTP.CONN_KEEP_ALIVE))
                    .stream()
                    .filter(h -> StringUtils.equalsIgnoreCase(h.getName(), "timeout")
                            && StringUtils.isNumeric(h.getValue()))
                    .findFirst()
                    .map(h -> NumberUtils.toLong(h.getValue(), DEFAULT_SECONDS))
                    .orElse(DEFAULT_SECONDS) * 1000;
            System.out.println(timeOut);
            return timeOut;

客户端http连接不允许复用

不推荐使用,这样完全发挥不错线程池的优势。

HttpPost httpPost = new HttpPost(url);
// 设置不使用长连接
httpPost.setHeader("Connection", "close");

服务端修改配置

不推荐,服务同时使用默认keepAlive 60s,connection timeout 60s。

https://blog.csdn.net/siantbaicn/article/details/80854528

前几天在项目联调中遇到接口报错org.apache.http.NoHttpResponseException:  failed to respond 。用postMan 等工具测试接口都正常,但是在应用中,就是报该错误,困扰了几天。后经过分析,我们应用中先调用了一个查询接口,紧接着又调用了其它接口,使用HttpClientUtils工具实现Http接口调用,用了HTTP链接池。由于对方提供的接口未... HttpClient 默认使用长连接+连接池。 Http客户端无法及时响应服务端关闭连接,这次如果继续使用这条连接去请求服务端就会导致 org.apache.http.NoHttpResponseException。 虽然HttpClient采取了很多方式避免这种情况,例如请求前会校验超时时间、会读socket检测连接是否还在,但是边界情况总是无法避免(这一刻判断连接可用后,在请求发出去后,接 文章目录org.apache.http.NoHttpResponseException: 目标服务地址 failed to respond创建HttpClient对象 org.apache.http.NoHttpResponseException: 目标服务地址 failed to respond ​ 在使用Httpclient去使用get请求去调用其他服务的时候出的这个错,但是我直接使用浏览器访... failed to respond 的原因是因为:Http 的 KeepAlive参数引起。 具体可以参考:https://blog.csdn.net/qq826654664jx/article/details/100864080 解决思路:http连接不允许复用; 解决代码: package com.phkj.equipment.util; import com.aliyun.oss.common.utils.HttpUtil; import org.apache.http.Const... 最近公司的spark离线任务稳定有报错日志: java.lang.RuntimeException: org.apache.http.NoHttpResponseException: demo.com:80 failed to respond 通过该报错日志我们可以判断是离线任务中使用的 httpclient 调用失败了,使用的组件版本如下: httpclient-4.5.12 httpcore-4.4.13 遇到问题首先是在 zuul1.x使用过程中,偶尔会出现failed to respond异常信息,对应的异常httpclient 的 NoHttpResponseException。 zuul作为client方连接nginx代理的服务,对应的设置为: zuul.host.max-per-route-connections=600 zuul.host.... jmeter调用接口报错403,postman正常 1、jmeter调用一个接口,报错403,Your last request has been blocked for security purposes. Please contact Web administrator with TOP_EVENTID: <80329879> for detail reasons.,以为是因为调用的域名,不是直接调用ip地址的问题,把请求改成了调用ip地址 2、请求改成ip地址,然后出现了新的报错 新项目上线遇到NoHttpResponseException的问题,大概11000笔发到C系统的交易会出现15笔会因这种异常而导致失败,对月交易量在近三亿的系统来说,按照这样的比例也会有4万多笔的交易失败,这种严重影响客户体验的现象坚决不能容忍。按照套路网上搜了下这种出现这种异常的原因以及解决办法,apache网站的解释是:In some circumstances,usually when un... 1、问题:这段时间使用jmeter压测时(300个请求,持续压300s,加速期10s),压力平稳时偶然错误,部分请求失败事务报错信息如下 org.apache.http.NoHttpResponseException: The target server failed to respond at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:95) at org.apa 1,出现场景:微信回调函数访问后发送模板消息,之前项目中使用的http的post请求没有问题,然后复制在新项目中,就报org.apache.http.NoHttpResponseException错误,后来在网上搜索了一大堆也没有解决问题,后面就调用其他post请求的数据类型的方式(xml,map,json)但是还是报错 2,后面就不断修改代码不断测试,直到将Content-Type的类型修改... HttpClient调用 首先我是在公司需求是要集成一个tts(文本转语言),然后调用我们引擎组写的接口,我这边用的是httpclient的post方式,写完之后用postman调用,一点问题没有,很完美,然后打包给测试,在应用上调用发现,断断续续,一段话,有的返回成功,有的则不返回 我这边的场景是,循环调用,如果只是一次调用,可能就不会有这个问题了 先看下报错信息 org.apache.http.NoHttpResponseException: host:端口 failed to respond