問題:
org.springframework.web.client.ResourceAccessException: I/O error on POST request for "https://www.xxxx.com/xxxx/xxxx/xxxx": Read timed out; nested exception is java.net.SocketTimeoutException: Read timed out
本地環(huán)境信息:Mac OS?10.14.5、JDK8
測試環(huán)境信息:Docker Linux 3.10+、JDK8
場景:
今天有一個功能,需要調(diào)用遠(yuǎn)程API,使用的是RestTemplate,在本地單元測試調(diào)用無誤后放到測試環(huán)境,發(fā)生了 read time out 的行為。
排查:
1.首先本地重試,并沒有發(fā)生超時的timeout。
2.聯(lián)想到由于是https請求,可能由于https證書的問題,于是配置了信任所有證書。(代碼放最后)
3.代碼里配置了信任所有證書,響應(yīng)就正常了。
Conclusion
????具體也沒有很深入的了解,本地debug時,看到SSL握手之后服務(wù)端有返回證書,構(gòu)造成X509對象,所以證書驗證時是通過的,具體可以看:org.apache.http.conn.ssl.SSLConnectionSocketFactory#verifyHostname 方法
? ? 由于沒有在Linux上跑,所以沒有得到最終的結(jié)論,mark一下吧。
@Bean
public RestTemplate restTemplate (RestTemplateBuilder builder) throws NoSuchAlgorithmException, KeyManagementException {
? ? TrustManager[] trustAllCerts =new TrustManager[] {
? ? ? ? ? ? new X509TrustManager() {
? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? public java.security.cert.X509Certificate[] getAcceptedIssuers() {
? ? ? ? ? ? ? ? ? ? return new X509Certificate[0];
}
? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? public void checkClientTrusted(
? ? ? ? ? ? ? ? ? ? ? ? java.security.cert.X509Certificate[] certs, String authType) {
}
? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? public void checkServerTrusted(
? ? ? ? ? ? ? ? ? ? ? ? java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
? ? SSLContext sslContext =SSLContext.getInstance("SSL");
? ? sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
? ? CloseableHttpClient httpClient =HttpClients.custom()
? ? ? ? ? ? .setSSLContext(sslContext)
? ? ? ? ? ? .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
? ? ? ? ? ? .build();
? ? HttpComponentsClientHttpRequestFactory customRequestFactory =new HttpComponentsClientHttpRequestFactory();
? ? customRequestFactory.setHttpClient(httpClient);
? ? RestTemplate restTemplate = builder.requestFactory(() ->customRequestFactory)
? ? ? ? ? ? .build();
? ? return builder.build();
}