版本说明

httpclinet:4.3.1 jdk:1.6 tomcat:6

异常信息

Caused by: javax.net.ssl.SSLException: Certificate for <**> doesn't contain CN or DNS subjectAlt
        at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:178)
        at org.apache.http.conn.ssl.BrowserCompatHostnameVerifier.verify(BrowserCompatHostnameVerifier.java:54)
        at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:152)
        at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:133)
        at org.apache.http.conn.ssl.SSLConnectionSocketFactory.verifyHostname(SSLConnectionSocketFactory.java:291)
        at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:262)
        at org.apache.http.impl.conn.HttpClientConnectionOperator.connect(HttpClientConnectionOperator.java:118)
        at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:314)
        at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:357)
        at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:218)
        at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:194)
        at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:85)
        at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:108)
        at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:186)
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:106)
        ... 18 more

背景

使用httpclient忽略证书发起https请求,代码如下

package cn.org.pcac.ries.httpService.util;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
public class HttpsSend {
	public static void main(String[] args) throws Exception {
		String url = "";
		List<NameValuePair> formparams = new ArrayList<NameValuePair>();
		HttpPost httpPost = new HttpPost(url);
		// 设置客户超时
		RequestConfig defaultRequestConfig = RequestConfig.custom()
				.setSocketTimeout(9000).setConnectTimeout(9000)
				.setConnectionRequestTimeout(9000)
				.setStaleConnectionCheckEnabled(true).build();
		// 设置服务端
		RequestConfig requestConfig = RequestConfig.copy(defaultRequestConfig)
				.build();
		formparams.add(new BasicNameValuePair("param", ""));
		httpPost.setConfig(requestConfig);
		CloseableHttpClient httpclient = null;
		httpclient = HttpClients.custom()
				.setDefaultRequestConfig(defaultRequestConfig).build();
		SSLContext sslcontext = null;
		if (url.indexOf("https") == 0) {
			sslcontext = createIgnoreVerifySSL();
			httpclient = HttpClients.custom().setDefaultRequestConfig(defaultRequestConfig)
					.setSslcontext(sslcontext).build();
		}
		UrlEncodedFormEntity uefEntity = new UrlEncodedFormEntity(formparams,
				"UTF-8");
		httpPost.setEntity(uefEntity);
		HttpResponse response = httpclient.execute(httpPost);
		HttpEntity entity = response.getEntity();
		if (entity != null) {
			// 获得返回报文
			String respons = EntityUtils.toString(entity, "UTF-8");
			EntityUtils.consume(entity);
			System.out.println(respons);
		}
	}
	public static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {  
	    SSLContext sc = SSLContext.getInstance("TLS");  
	    X509TrustManager trustManager = new X509TrustManager() {  
	        @Override  
	        public void checkClientTrusted(  
	                java.security.cert.X509Certificate[] paramArrayOfX509Certificate,  
	                String paramString) throws CertificateException {  
	        }  
	  
	        @Override  
	        public void checkServerTrusted(  
	                java.security.cert.X509Certificate[] paramArrayOfX509Certificate,  
	                String paramString) throws CertificateException {  
	        }  
	  
	        @Override  
	        public java.security.cert.X509Certificate[] getAcceptedIssuers() {  
	            return null;  
	        }  
	    };  
	  
	    sc.init(null, new TrustManager[] { trustManager }, null);  
	    return sc;  
	} 
}

错误原因

跟踪源码,异常信息如下所示: 访问网站的证书为自签证书,缺少CN=等信息,但是我已经忽略证书校验了为什么还会出现这个问题呢? 发现初始化CloseableHttpClient时,有如下代码: 因此修改初始化CloseableHttpClient,将 httpclient = HttpClients.custom().setDefaultRequestConfig(defaultRequestConfig) .setSslcontext(sslcontext).build(); 改成 httpclient = HttpClients.custom().setDefaultRequestConfig(defaultRequestConfig) .setHostnameVerifier(hostnameVerifier) .setSslcontext(sslcontext).build(); 增加变量 public static X509HostnameVerifier hostnameVerifier = new X509HostnameVerifier() { @Override public boolean verify(String arg0, SSLSession arg1) { return true; }

	@Override
	public void verify(String host, String[] cns, String[] subjectAlts)
			throws SSLException {
		
	}
	
	@Override
	public void verify(String host, X509Certificate cert) throws SSLException {
		
	}
	
	@Override
	public void verify(String host, SSLSocket ssl) throws IOException {
		
	}
};