最近项目中利用httpclient时,访问接口报错。错误信息如下:
错误原因分析:
并发调用同一个httpclient去请求数据导致,当上一个post|get请求尚未结束时,又启新的线程再次使用该httpclient请求数据。
解决方案:
采用线程池,从线程池中获取httpclient。
这里贴出服务器访问https\http链接类型接口完整代码,
使用方法:
String url = "**/**/**/setCustomerInfo";
String xml = "*****";
Map<String, String> param = new HashMap<>();
param.put("sb", xml);
String results = SSLHttpHelper.getHelper().post(url, param);
JSONObject jsonObject = new JSONObject(results);
// 解析返回的xml
if (!(jsonObject.get("result").toString().equals("false"))) {
Document docData = DocumentHelper.parseText(jsonObject.get("responsMess").toString());
Element rootElt = docData.getRootElement();
Element element = rootElt.element("Body").element("SyncCustomerInfoResponse").element("SyncCustomerInfoResult");
String text = element.getText();
JSONObject data = new JSONObject(text);
return data;
}
SSLHttpHelper.java
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import org.apache.commons.collections.MapUtils;
import org.apache.http.Consts;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.NameValuePair;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
public class SSLHttpHelper {
// 创建HostnameVerifier
// 用于解决javax.net.ssl.SSLException: hostname in certificate didn't match:
static HostnameVerifier hostnameVerifier = new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
};
private static SSLHttpHelper instance = new SSLHttpHelper();
public static SSLHttpHelper getHelper() {
return instance;
}
private static CloseableHttpClient httpsClient = null;
private static CloseableHttpClient httpClient = null;
static {
httpClient = getHttpClient();
httpsClient = getHttpsClient();
}
//利用PoolManager获取连接
public static CloseableHttpClient getHttpClient() {
try {
httpClient = HttpClients.custom().setConnectionManager(PoolManager.getHttpPoolInstance())
.setConnectionManagerShared(true).setDefaultRequestConfig(requestConfig())
.setRetryHandler(retryHandler()).build();
} catch (Exception e) {
e.printStackTrace();
}
return httpClient;
}
//利用PoolsManager获取连接
public static CloseableHttpClient getHttpsClient() {
try {
SSLContext ctx = SSLContext.getInstance("SSL");
TrustManager[] trustAllCerts = { new TrustAllTrustManager() };
ctx.init(null, trustAllCerts, null);
ConnectionSocketFactory connectionSocketFactory = new SSLConnectionSocketFactory(ctx, hostnameVerifier);
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
.register("http", PlainConnectionSocketFactory.INSTANCE).register("https", connectionSocketFactory)
.build();
// 设置连接池
httpsClient = HttpClients.custom()
.setConnectionManager(PoolsManager.getHttpsPoolInstance(socketFactoryRegistry))
.setConnectionManagerShared(true).setDefaultRequestConfig(requestConfig())
.setRetryHandler(retryHandler()).build();
} catch (Exception e) {
e.printStackTrace();
}
return httpsClient;
}
// 配置请求的超时设置
// 首先设置全局的标准cookie策略
public static RequestConfig requestConfig() {
RequestConfig requestConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD_STRICT)
.setConnectionRequestTimeout(20000).setConnectTimeout(20000).setSocketTimeout(20000).build();
return requestConfig;
}
public static HttpRequestRetryHandler retryHandler() {
// 请求重试处理
HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() {
public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
if (executionCount >= 5) {// 如果已经重试了5次,就放弃
return false;
}
if (exception instanceof NoHttpResponseException) {// 如果服务器丢掉了连接,那么就重试
return true;
}
if (exception instanceof SSLHandshakeException) {// 不要重试SSL握手异常
return false;
}
if (exception instanceof InterruptedIOException) {// 超时
return false;
}
if (exception instanceof UnknownHostException) {// 目标服务器不可达
return false;
}
if (exception instanceof ConnectTimeoutException) {// 连接被拒绝
return false;
}
if (exception instanceof SSLException) {// ssl握手异常
return false;
}
HttpClientContext clientContext = HttpClientContext.adapt(context);
HttpRequest request = clientContext.getRequest();
// 如果请求是幂等的,就再次尝试
if (!(request instanceof HttpEntityEnclosingRequest)) {
return true;
}
return false;
}
};
return httpRequestRetryHandler;
}
public String post(String httpUrl, Map<String, String> request) {
String result = "";
CloseableHttpClient httpClient = getHttpClient();
try {
HttpPost httpPost = new HttpPost(httpUrl);
if(!MapUtils.isEmpty(request)){
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
for (Iterator<Map.Entry<String, String>> iterator = request.entrySet().iterator(); iterator.hasNext();) {
Map.Entry<String, String> entry = iterator.next();
nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
httpPost.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8));
}
CloseableHttpResponse response = httpsClient.execute(httpPost);
result = EntityUtils.toString(response.getEntity());
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
public String httpPost(String httpUrl, Map<String, String> request) {
String result = "";
CloseableHttpClient httpClient = getHttpClient();
try {
HttpPost httpPost = new HttpPost(httpUrl);
if(!MapUtils.isEmpty(request)){
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
for (Iterator<Map.Entry<String, String>> iterator = request.entrySet().iterator(); iterator.hasNext();) {
Map.Entry<String, String> entry = iterator.next();
nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
httpPost.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8));
}
CloseableHttpResponse response = httpClient.execute(httpPost);
result = EntityUtils.toString(response.getEntity());
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
//连接池
public static class PoolManager {
public static PoolingHttpClientConnectionManager clientConnectionManager = null;
private static int maxTotal = 200;
private static int defaultMaxPerRoute = 100;
private PoolManager() {
clientConnectionManager.setMaxTotal(maxTotal);
clientConnectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute);
}
private static class PoolManagerHolder {
public static PoolManager instance = new PoolManager();
}
public static PoolManager getInstance() {
if (null == clientConnectionManager)
clientConnectionManager = new PoolingHttpClientConnectionManager();
return PoolManagerHolder.instance;
}
public static PoolingHttpClientConnectionManager getHttpPoolInstance() {
PoolManager.getInstance();
return PoolManager.clientConnectionManager;
}
}
//连接池
public static class PoolsManager {
public static PoolingHttpClientConnectionManager clientConnectionManager = null;
private static int maxTotal = 200;
private static int defaultMaxPerRoute = 100;
private PoolsManager() {
clientConnectionManager.setMaxTotal(maxTotal);
clientConnectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute);
}
private static class PoolsManagerHolder {
public static PoolsManager instance = new PoolsManager();
}
public static PoolsManager getInstance(Registry<ConnectionSocketFactory> socketFactoryRegistry) {
if (null == clientConnectionManager)
clientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
return PoolsManagerHolder.instance;
}
public static PoolingHttpClientConnectionManager getHttpsPoolInstance(Registry<ConnectionSocketFactory> socketFactoryRegistry) {
PoolsManager.getInstance(socketFactoryRegistry);
return PoolsManager.clientConnectionManager;
}
}
}
TrustAllTrustManager.java
public class TrustAllTrustManager implements javax.net.ssl.TrustManager, javax.net.ssl.X509TrustManager {
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)
throws java.security.cert.CertificateException {
return;
}
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType)
throws java.security.cert.CertificateException {
return;
}
}