版本说明

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 formparams = new ArrayList();
        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;  
    } 
}

错误原因

跟踪源码,异常信息如下所示:
记录一下访问https报doesn't contain CN or DNS sub错误_第1张图片
记录一下访问https报doesn't contain CN or DNS sub错误_第2张图片
记录一下访问https报doesn't contain CN or DNS sub错误_第3张图片
访问网站的证书为自签证书,缺少CN=等信息,但是我已经忽略证书校验了为什么还会出现这个问题呢?
发现初始化CloseableHttpClient时,有如下代码:
记录一下访问https报doesn't contain CN or DNS sub错误_第4张图片
因此修改初始化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() {br/>@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 {

    }
};