工作中需要对接某第三方支付公司,其对外提供https服务(不需要证书),8583报文。生产环境下,近期忽然出现超时的情况,表现是程序抛出异常java.net.SocketTimeoutException: Read timed out。查看日志,发现才5秒时间,没有到超时时间,找上游沟通,反馈说是1秒正常返回了。
首先怀疑是网络问题,由于是互联网对接,网络问题不好确认,于是用tcpdump在系统中抓包观察,发现以下问题:,服务端通知客户端Encrypted Alert(没有发数据),客户端断开连接。由此可知不是网络问题。
再次和上游确认,上游系统用到httpclient4.3,客户端使用httpclient3.1,考虑可能是该问题导致,于是升级客户端版本,改造程序如下:
private String writePost(String url, String content) throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
SSLContext sslContext = SSLContexts.custom().useTLS().loadTrustMaterial(null, new TrustStrategy() {
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
return true;
}
}).build();
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, new AllowAllHostnameVerifier());
Registry
.register("https", sslConnectionSocketFactory)
.build();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(r);
cm.setMaxTotal(500);
cm.setDefaultMaxPerRoute(350);
SocketConfig socketConfig = SocketConfig.custom()
.setSoKeepAlive(true)
.setTcpNoDelay(true)
.setSoTimeout(timeout)
.build();
cm.setDefaultSocketConfig(socketConfig);
RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(timeout).setConnectTimeout(timeout).setSocketTimeout(timeout).build();
//创建httpClient
CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(cm)
.setDefaultRequestConfig(requestConfig)
.build();
HttpPost httpPost = new HttpPost(url);
String response="";
try {
if (null != content) {
byte[] bs= hexConvert.str10Bcd(content);
ByteArrayEntity arrayEntity = new ByteArrayEntity(bs);
httpPost.setEntity(arrayEntity);
}
CloseableHttpResponse result = httpClient.execute(httpPost);
//请求发送成功,并得到响应
log.info("httpstatus:"+result.getStatusLine().getStatusCode());
if (result.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
try {
HttpEntity entity = result.getEntity();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
InputStream inputStream = entity.getContent();
int chunk=0;
byte[] tmp = new byte[4096];
while ((chunk = inputStream.read(tmp)) != -1) {
buffer.write(tmp, 0, chunk);
}
byte[] stuff = buffer.toByteArray();
response = hexConvert.byte2HexString(stuff);
} catch (Exception e) {
log.error("post请求提交失败:" + url, e);
}
}
} catch (Exception e) {
log.info("执行Post请求" + url + "时,发生异常!"+ e);
} finally {
httpPost.releaseConnection();
}
return response;
}
改造完成后每笔交易都会有Encrypted Alert,但是数据正常获取到,使用到的协议已经变成了TLSV1.2,升级前使用TLSV1.1,正常交易没有Encrypted Alert,异常交易才会有Encrypted Alert。