java.net.SocketException: Software caused connection abort: recv failed
之前写的https请求莫名其妙报了这个错误,之前是没有一点问题的啊。代码如下
public static String doPost(String url, Map<String, String> paramsMap) {
try {
DefaultHttpClient client =null;
//支持https
if(url.startsWith("https")){
client= new SSLClient();
}else{
client = new DefaultHttpClient();
}
HttpPost httppost = new HttpPost(url);
String userAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36";
httppost.setHeader("User-Agent", userAgent);
// 设置参数
if (paramsMap != null) {
List<NameValuePair> params = new ArrayList<NameValuePair>();
for (String key : paramsMap.keySet()) {
params.add(new BasicNameValuePair(key, paramsMap.get(key)));
}
httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
}
// 发送请求
HttpResponse httpresponse = client.execute(httppost);
HttpEntity entity = httpresponse.getEntity();
return EntityUtils.toString(entity);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//设置信任所有证书
public class SSLClient extends DefaultHttpClient{
public SSLClient() throws Exception{
super();
SSLContext ctx = SSLContext.getInstance("TLS");
//SSLContext ctx = SSLContext.getInstance("SSL");
X509TrustManager tm = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
ctx.init(null, new TrustManager[]{tm}, null);
SSLSocketFactory ssf = new SSLSocketFactory(ctx,SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
ClientConnectionManager ccm = this.getConnectionManager();
SchemeRegistry sr = ccm.getSchemeRegistry();
sr.register(new Scheme("https", 443, ssf));
}
}
这个方法是公用的,而且用请求工具访问对方提供的URL是可以获取返回结果的,问号脸??
那显然是我这个httpClient请求的问题了,百度看了很多回答也没有一点头绪,最后问了大牛同事看了看说现在的httpClient请求不提倡这么写了
CloseableHttpClient client = HttpClients.createDefault();
CloseableHttpResponse httpresponse = client.execute(httppost);
纳尼?就没有问题了!返回结果了!
原来DefaultHttpClient这个实现类虽然可以继续用,但不在被维护也就是废弃掉了,现在用的是CloseableHttpResponse 这个实现类。
但是为什么会出这个错误呢 可能是它的不稳定性导致的吧 还是不太清楚 问题倒总算是解决了。
我用的是httpClient4.4的jar包 希望大家也采用后一种方法吧。修改后的代码如下:
public static String doPostNew(String url, Map<String, String> paramsMap) {
SSLContext ssl = null;
try {
ssl = createIgnoreVerifySSL();
} catch (KeyManagementException e1) {
e1.printStackTrace();
} catch (NoSuchAlgorithmException e1) {
e1.printStackTrace();
}
// 设置协议http和https对应的处理socket链接工厂的对象
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https", new SSLConnectionSocketFactory(ssl))
.build();
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
HttpClients.custom().setConnectionManager(connManager);
//创建自定义的httpclient对象
CloseableHttpClient client = HttpClients.custom().setConnectionManager(connManager).build();
try {
HttpPost httppost = new HttpPost(url);
String userAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36";
httppost.setHeader("User-Agent", userAgent);
// 设置参数
if (paramsMap != null) {
List<NameValuePair> params = new ArrayList<NameValuePair>();
for (String key : paramsMap.keySet()) {
params.add(new BasicNameValuePair(key, paramsMap.get(key)));
}
httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
}
// 发送请求
CloseableHttpResponse httpresponse = client.execute(httppost);
HttpEntity entity = httpresponse.getEntity();
return EntityUtils.toString(entity);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
finally{
client.getConnectionManager().shutdown();//用完了释放连接
}
return null;
}
public static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {
SSLContext sc = SSLContext.getInstance("TLS");
// 实现一个X509TrustManager接口,用于绕过验证,即信任所有证书
X509TrustManager trustManager = new X509TrustManager() {
public void checkClientTrusted(
java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
String paramString) throws CertificateException {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
String paramString) throws CertificateException {
}
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
};
sc.init(null, new TrustManager[] { trustManager }, null);
return sc;
}
修改之后上面的问题是解决了,但是另一个URL出现了新问题Host name '' does not match the certificate subject provided by the peer
研究发现原来是对方本来提供的https地址就有问题,如下:
又研究了下,为什么之前不会报错呢?
SSLSocketFactory ssf = new SSLSocketFactory(ctx,SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
就是在这里初始化SSLSocketFactory的时候会多加一个参数:允许所有Hostname验证。同理:
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https", new SSLConnectionSocketFactory(ssl,SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER))
.build();
问题解决。