最近一个现场在使用应用访问SSO时频繁出现 Connection timed out: connect,导致应用卡顿,挂机频繁, 由于是使用了HttpClient。
后来查了查资料 此问题出现原因是并发调用同一个httpclient去请求数据。在上一个请求尚未结束时,又启新的线程再次使用该httpclient请求数据,因为 httpclient 我用的是一个静态常量 ,应用中只有一个,导致问题出现。
现在有2个解决方案:
加个synchronized,这个方法是避免了报错,以不会出现多个同时操作,同步大家 都知道 ,但有一个问题就是如果一个请求不通时,耗时是相当长,这样在要求多并发的应用中是不符的。
把httpclient 变成成员变量,每次使用的时候都初始化,用完了close关闭,这样解决了并发问题,但经过测试大概3000的并发吧,用多线程同时使用,再多由于网络原因PC机就已经断网了。
目前我的解决方法是用第2种把httpclient变成成员变量, 本人对httpclient不精通,有更好解决方法的大神,请不吝赐教!
分享一下代码:
/**
* HTTP Get 获取内容
* @param url请求的url地址 ?之前的地址
* @param params请求的参数
* @return 页面内容
*/
public static String sendGet(String url, Map<String, Object> params) throws ParseException, UnsupportedEncodingException, IOException{
return sendGet(url, params,null);
}
public static String sendGet(String url, Map<String, Object> params,Map<String, Object>headers) throws ParseException, UnsupportedEncodingException, IOException{
if(params !=null && !params.isEmpty()){
List<NameValuePair> pairs = new ArrayList<NameValuePair>(params.size());
for (String key :params.keySet()){
pairs.add(new BasicNameValuePair(key, params.get(key).toString()));
}
url +="?"+EntityUtils.toString(new UrlEncodedFormEntity(pairs), CHARSET);
}
HttpGet httpGet = new HttpGet(url);
if (headers != null && !headers.isEmpty()) {
for (String key : headers.keySet()) {
httpGet.setHeader(key, headers.get(key).toString());
}
}
CloseableHttpClient httpClient = buildClient();
CloseableHttpResponse response = httpClient.execute(httpGet);
int statusCode = response.getStatusLine().getStatusCode();
if(statusCode !=200){
httpGet.abort();
throw new RuntimeException("HttpClient,error status code :" + statusCode);
}
HttpEntity entity = response.getEntity();
String result = null;
if (entity != null) {
result = EntityUtils.toString(entity, "utf-8");
EntityUtils.consume(entity);
response.close();
httpClient.close();
return result;
}else{
return null;
}
}
我把 buildClient() 方法也拿出来分享一下, 此方法已经适配了 适配X509证书
/**
* 适配X509证书
* @return
*/
private static CloseableHttpClient buildClient(){
RequestConfig config = RequestConfig.custom().setConnectTimeout(-1).setSocketTimeout(-1).build();
X509TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
SSLContext ctx = null;
try {
ctx = SSLContext.getInstance("TLS");
ctx.init(null, new TrustManager[] { tm }, null);
} catch (KeyManagementException e) {
logger.debug("context", e);
} catch (NoSuchAlgorithmException e) {
logger.debug("context", e);
}
HttpClientBuilder builder = HttpClientBuilder.create();
SSLConnectionSocketFactory sslConnectionFactory = new SSLConnectionSocketFactory(ctx,
NoopHostnameVerifier.INSTANCE);
builder.setSSLSocketFactory(sslConnectionFactory);
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory> create()
.register("https", sslConnectionFactory).register("http", PlainConnectionSocketFactory.getSocketFactory()).build();
HttpClientConnectionManager ccm1 = new BasicHttpClientConnectionManager(registry);
builder.setConnectionManager(ccm1);
return builder.setDefaultRequestConfig(config).build();
}