https nested exception is org.apache.http.NoHttpResponseException: ****:443 failed to respond

RestTemplate 调用 https的域名时:出现  nested exception is org.apache.http.NoHttpResponseException: ****:443 failed to respond 错误

 

现象:

org.springframework.web.client.ResourceAccessException: I/O error on POST request for "https://***.com/*": ***:443 failed to respond; nested exception is org.apache.http.NoHttpResponseException: ***:443 failed to respond
	at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:673)
	at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:620)
	at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:387)
	at com.zkh360.sim.service.kh.impl.KhServiceImpl.requestTransportationTime(KhServiceImpl.java:345)
	at com.zkh360.sim.service.date.impl.EstimateDeliveryTimeServiceImpl.acquireTransTime(EstimateDeliveryTimeServiceImpl.java:1176)
	at com.zkh360.sim.service.date.impl.EstimateDeliveryTimeServiceImpl.calculateEstimateDeliveryDate(EstimateDeliveryTimeServiceImpl.java:1134)
	at com.zkh360.sim.api.DateRelatedApi.lambda$findEstimateDeliveryDate$1(DateRelatedApi.java:135)
	at org.springframework.cloud.sleuth.instrument.async.SpanContinuingTraceCallable.call(SpanContinuingTraceCallable.java:54)
	at org.springframework.web.context.request.async.WebAsyncManager$5.run(WebAsyncManager.java:327)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.lang.Thread.run(Thread.java:748)

原因分析:
RestTemplate 自带链接池,下次使用时,连接池已经断开了;所以会出现上面的 错误。

 

解决办法:

RestTemplate 里面使用 短连接。



import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;

import java.io.IOException;

/**
 * 短连接
 * @author cloudyue
 */
@Slf4j
public class ClientHttpRequestConnectionCloseInterceptor implements ClientHttpRequestInterceptor {

    private static final String NO_CONNECTION_UPDATE = "NoConnectionUpdate";

    private static final String CONNECTION_UP = "Connection";

    private static final String CONNECTION_LOW = "connection";

    @Override
    public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {

        try {
            HttpHeaders headers = httpRequest.getHeaders();
            if (headers.containsKey(NO_CONNECTION_UPDATE)) {
                log.info("skip connection intercept");
            } else {
                if (!headers.containsKey(CONNECTION_UP) && !headers.containsKey(CONNECTION_LOW)) {
                    headers.set(CONNECTION_LOW, "close");
                }
            }
        } catch (Exception e) {
            log.error("http request intercept fail, {}", e.getMessage(), e);
        }

        return clientHttpRequestExecution.execute(httpRequest, bytes);
    }
}

RestTemplute配置:


import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.SSLContext;

/**
 * @desc: RestTemplateConfig.java
 * @author: cloud.yue
 */
@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new HookedRestTemplate(generateHttpsRequestFactory())
        restTemplate.getInterceptors()
                // 默认使用短连接
                .add(new ClientHttpRequestConnectionCloseInterceptor());
        return restTemplate;

    }

    public HttpComponentsClientHttpRequestFactory generateHttpsRequestFactory() {
        try {
            TrustStrategy acceptingTrustStrategy = (x509Certificates, authType) -> true;
            SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
            SSLConnectionSocketFactory connectionSocketFactory = new SSLConnectionSocketFactory(sslContext, new NoopHostnameVerifier());

            HttpClientBuilder httpClientBuilder = HttpClients.custom();
            httpClientBuilder.setSSLSocketFactory(connectionSocketFactory);
            CloseableHttpClient httpClient = httpClientBuilder.build();
            HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
            factory.setHttpClient(httpClient);
            factory.setConnectTimeout(60 * 1000);
            factory.setReadTimeout(60 * 1000);
            return factory;
        } catch (Exception e) {
            throw new RuntimeException("创建HttpsRestTemplate失败", e);
        }
    }

}

 

你可能感兴趣的:(https nested exception is org.apache.http.NoHttpResponseException: ****:443 failed to respond)